Compare commits
No commits in common. "master" and "v0.2.2" have entirely different histories.
187 changed files with 4455 additions and 16621 deletions
66
Automation/Automation.cs
Normal file
66
Automation/Automation.cs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace Automation
|
||||||
|
{
|
||||||
|
class Automation
|
||||||
|
{
|
||||||
|
private static readonly string Name = "automation";
|
||||||
|
|
||||||
|
private static readonly string XmlPrefix = "<!--Start Dependencies-->\n <ItemGroup>\n";
|
||||||
|
private static readonly string XmlSuffix = " </ItemGroup>\n<!--End Dependencies-->";
|
||||||
|
|
||||||
|
private static readonly string GamecraftModdingAPI_csproj = @"\GamecraftModdingAPI.csproj";
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length != 2 || args[0] == "-h" || args[0] == "--help")
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Usage : {Name}.exe <path to Gamecraft DLLs> <path to GamecraftModdingAPI.csproj>");
|
||||||
|
Console.WriteLine("Other arguments:");
|
||||||
|
Console.WriteLine(" --help : display this message");
|
||||||
|
Console.WriteLine($" --version : display {Name}'s version");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Console.WriteLine("Building Assembly references");
|
||||||
|
string asmXml = BuildAssemblyReferencesXML(args[0]);
|
||||||
|
//Console.WriteLine(asmXml);
|
||||||
|
string csprojPath = args[1].EndsWith(GamecraftModdingAPI_csproj)? args[1] : args[1]+GamecraftModdingAPI_csproj;
|
||||||
|
Console.WriteLine($"Parsing {csprojPath}");
|
||||||
|
string csprojContents = File.ReadAllText(csprojPath);
|
||||||
|
Match dependenciesStart = (new Regex(@"<\s*!--\s*Start\s+Dependencies\s*--\s*>", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline)).Match(csprojContents);
|
||||||
|
Match dependenciesEnd = (new Regex(@"<\s*!--\s*End\s+Dependencies\s*--\s*>", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline)).Match(csprojContents);
|
||||||
|
if (!dependenciesEnd.Success || !dependenciesStart.Success)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Unable to find dependency XML comments, aborting!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
csprojContents = csprojContents.Substring(0, dependenciesStart.Index) + asmXml + csprojContents.Substring(dependenciesEnd.Index+dependenciesEnd.Length);
|
||||||
|
//Console.WriteLine(csprojContents);
|
||||||
|
Console.WriteLine($"Writing Assembly references into {csprojPath}");
|
||||||
|
File.WriteAllText(csprojPath, csprojContents);
|
||||||
|
Console.WriteLine("Successfully generated Gamecraft assembly DLL references");
|
||||||
|
}
|
||||||
|
|
||||||
|
static string BuildAssemblyReferencesXML(string path)
|
||||||
|
{
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
result.Append(XmlPrefix);
|
||||||
|
string[] files = Directory.GetFiles(path, "*.dll");
|
||||||
|
for(int i = 0; i<files.Length; i++)
|
||||||
|
{
|
||||||
|
if (files[i].Contains(@"\System.") || files[i].EndsWith(@"mscorlib.dll") || files[i].Contains(@"\Mono."))
|
||||||
|
{
|
||||||
|
// no
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Append($" <Reference Include=\"{files[i].Substring(files[i].LastIndexOf(@"\") + 1).Replace(".dll", "")}\">\n <HintPath>{files[i]}</HintPath>\n </Reference>\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.Append(XmlSuffix);
|
||||||
|
return result.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
Automation/Automation.csproj
Normal file
8
Automation/Automation.csproj
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -1,67 +0,0 @@
|
||||||
#!/usr/bin/python3
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import re
|
|
||||||
# this assumes a mostly semver-complient version number
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser(description="Increment TechbloxModdingAPI 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("../TechbloxModdingAPI/TechbloxModdingAPI.csproj", "r") as xmlFile:
|
|
||||||
print("Parsing TechbloxModdingAPI.csproj")
|
|
||||||
fileStr = xmlFile.read()
|
|
||||||
versionMatch = re.search(r"<Version>(.+)</Version>", fileStr)
|
|
||||||
if versionMatch is None:
|
|
||||||
print("Unable to find version number in TechbloxModdingAPI.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("../TechbloxModdingAPI/TechbloxModdingAPI.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)
|
|
|
@ -1,62 +0,0 @@
|
||||||
#!/usr/bin/python3
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
from pathlib import Path, PurePath
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
|
|
||||||
DLL_EXCLUSIONS_REGEX = r"(System|Microsoft|Mono|IronPython|DiscordRPC|IllusionInjector|IllusionPlugin|netstandard)\."
|
|
||||||
|
|
||||||
def getAssemblyReferences(path):
|
|
||||||
asmDir = Path(path)
|
|
||||||
result = list()
|
|
||||||
addedPath = ""
|
|
||||||
if not asmDir.exists():
|
|
||||||
addedPath = "../"
|
|
||||||
asmDir = Path(addedPath + path)
|
|
||||||
for child in asmDir.iterdir():
|
|
||||||
if child.is_file() and re.search(DLL_EXCLUSIONS_REGEX, str(child)) is None and str(child).lower().endswith(".dll"):
|
|
||||||
childstr = str(child)
|
|
||||||
childstr = os.path.relpath(childstr, addedPath).replace("\\", "/")
|
|
||||||
result.append(childstr)
|
|
||||||
result.sort(key=str.lower)
|
|
||||||
result = [path + "/IllusionInjector.dll", path + "/IllusionPlugin.dll"] + result # Always put it on top
|
|
||||||
return result
|
|
||||||
|
|
||||||
def buildReferencesXml(path):
|
|
||||||
assemblyPathes = getAssemblyReferences(path)
|
|
||||||
result = list()
|
|
||||||
for asm in assemblyPathes:
|
|
||||||
asmPath = str(asm)
|
|
||||||
xml = " <Reference Include=\"" + asmPath[asmPath.rfind("/") + 1:].replace(".dll", "") + "\">\n" \
|
|
||||||
+ " <HintPath>" + asmPath.replace("/", "\\") + "</HintPath>\n" \
|
|
||||||
+ " <HintPath>..\\" + asmPath.replace("/", "\\") + "</HintPath>\n" \
|
|
||||||
+ " </Reference>\n"
|
|
||||||
result.append(xml)
|
|
||||||
return "<!--Start Dependencies-->\n <ItemGroup>\n" + "".join(result) + " </ItemGroup>\n<!--End Dependencies-->"
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser(description="Generate TechbloxModdingAPI.csproj")
|
|
||||||
# TODO (maybe?): add params for custom csproj read and write locations
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
print("Building Assembly references")
|
|
||||||
asmXml = buildReferencesXml("../ref_TB/Techblox_Data/Managed")
|
|
||||||
# print(asmXml)
|
|
||||||
|
|
||||||
with open("../TechbloxModdingAPI/TechbloxModdingAPI.csproj", "r") as xmlFile:
|
|
||||||
print("Parsing TechbloxModdingAPI.csproj")
|
|
||||||
fileStr = xmlFile.read()
|
|
||||||
# print(fileStr)
|
|
||||||
depsStart = re.search(r"\<!--\s*Start\s+Dependencies\s*--\>", fileStr)
|
|
||||||
depsEnd = re.search(r"\<!--\s*End\s+Dependencies\s*--\>", fileStr)
|
|
||||||
if depsStart is None or depsEnd is None:
|
|
||||||
print("Unable to find dependency XML comments, aborting!")
|
|
||||||
exit(1)
|
|
||||||
newFileStr = fileStr[:depsStart.start() - 1] + "\n" + asmXml + "\n" + fileStr[depsEnd.end() + 1:]
|
|
||||||
with open("../TechbloxModdingAPI/TechbloxModdingAPI.csproj", "w") as xmlFile:
|
|
||||||
print("Writing Assembly references")
|
|
||||||
xmlFile.write(newFileStr)
|
|
||||||
# print(newFileStr)
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><configuration>
|
|
||||||
<runtime>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="mscorlib" publicKeyToken="b77a5c561934e089" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
</runtime>
|
|
||||||
</configuration>
|
|
|
@ -1,158 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.CodeDom;
|
|
||||||
using System.CodeDom.Compiler;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using Gamecraft.Tweaks;
|
|
||||||
using RobocraftX.Common;
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
namespace CodeGenerator
|
|
||||||
{
|
|
||||||
public class BlockClassGenerator
|
|
||||||
{
|
|
||||||
public void Generate(string name, string group = null, Dictionary<string, string> renames = null, params Type[] types)
|
|
||||||
{
|
|
||||||
if (group is null)
|
|
||||||
{
|
|
||||||
group = GetGroup(name) + "_BLOCK_GROUP";
|
|
||||||
if (typeof(CommonExclusiveGroups).GetFields().All(field => field.Name != group))
|
|
||||||
group = GetGroup(name) + "_BLOCK_BUILD_GROUP";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!group.Contains('.'))
|
|
||||||
group = "CommonExclusiveGroups." + group;
|
|
||||||
|
|
||||||
var codeUnit = new CodeCompileUnit();
|
|
||||||
var ns = new CodeNamespace("TechbloxModdingAPI.Blocks");
|
|
||||||
ns.Imports.Add(new CodeNamespaceImport("RobocraftX.Common"));
|
|
||||||
ns.Imports.Add(new CodeNamespaceImport("Svelto.ECS"));
|
|
||||||
var cl = new CodeTypeDeclaration(name);
|
|
||||||
//cl.BaseTypes.Add(baseClass != null ? new CodeTypeReference(baseClass) : new CodeTypeReference("Block"));
|
|
||||||
cl.BaseTypes.Add(new CodeTypeReference("SignalingBlock"));
|
|
||||||
cl.Members.Add(new CodeConstructor
|
|
||||||
{
|
|
||||||
Parameters = {new CodeParameterDeclarationExpression("EGID", "egid")},
|
|
||||||
Comments =
|
|
||||||
{
|
|
||||||
_start, new CodeCommentStatement($"Constructs a(n) {name} object representing an existing block.", true), _end
|
|
||||||
},
|
|
||||||
BaseConstructorArgs = {new CodeVariableReferenceExpression("egid")},
|
|
||||||
Attributes = MemberAttributes.Public | MemberAttributes.Final
|
|
||||||
});
|
|
||||||
cl.Members.Add(new CodeConstructor
|
|
||||||
{
|
|
||||||
Parameters =
|
|
||||||
{
|
|
||||||
new CodeParameterDeclarationExpression(typeof(uint), "id")
|
|
||||||
},
|
|
||||||
Comments =
|
|
||||||
{
|
|
||||||
_start, new CodeCommentStatement($"Constructs a(n) {name} object representing an existing block.", true), _end
|
|
||||||
},
|
|
||||||
BaseConstructorArgs =
|
|
||||||
{
|
|
||||||
new CodeObjectCreateExpression("EGID", new CodeVariableReferenceExpression("id"),
|
|
||||||
new CodeVariableReferenceExpression(group))
|
|
||||||
},
|
|
||||||
Attributes = MemberAttributes.Public | MemberAttributes.Final
|
|
||||||
});
|
|
||||||
foreach (var type in types)
|
|
||||||
{
|
|
||||||
GenerateProperties(cl, type, name, renames);
|
|
||||||
}
|
|
||||||
ns.Types.Add(cl);
|
|
||||||
codeUnit.Namespaces.Add(ns);
|
|
||||||
|
|
||||||
var provider = CodeDomProvider.CreateProvider("CSharp");
|
|
||||||
var path = $@"../../../../TechbloxModdingAPI/Blocks/{name}.cs";
|
|
||||||
using (var sw = new StreamWriter(path))
|
|
||||||
{
|
|
||||||
provider.GenerateCodeFromCompileUnit(codeUnit, sw, new CodeGeneratorOptions {BracingStyle = "C"});
|
|
||||||
}
|
|
||||||
|
|
||||||
File.WriteAllLines(path,
|
|
||||||
File.ReadAllLines(path).SkipWhile(line => line.StartsWith("//") || line.Length == 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetGroup(string name)
|
|
||||||
{
|
|
||||||
var ret = "";
|
|
||||||
foreach (var ch in name)
|
|
||||||
{
|
|
||||||
if (char.IsUpper(ch) && ret.Length > 0)
|
|
||||||
ret += "_" + ch;
|
|
||||||
else
|
|
||||||
ret += char.ToUpper(ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GenerateProperties(CodeTypeDeclaration cl, Type type, string baseClass,
|
|
||||||
Dictionary<string, string> renames)
|
|
||||||
{
|
|
||||||
if (!typeof(IEntityComponent).IsAssignableFrom(type))
|
|
||||||
throw new ArgumentException("Type must be an entity component");
|
|
||||||
bool reflection = type.IsNotPublic;
|
|
||||||
var reflectedType = new CodeSnippetExpression($"HarmonyLib.AccessTools.TypeByName(\"{type.FullName}\")");
|
|
||||||
foreach (var field in type.GetFields())
|
|
||||||
{
|
|
||||||
var attr = field.GetCustomAttribute<TweakableStatAttribute>();
|
|
||||||
if (renames == null || !renames.TryGetValue(field.Name, out var propName))
|
|
||||||
{
|
|
||||||
propName = field.Name;
|
|
||||||
if (attr != null)
|
|
||||||
propName = attr.propertyName;
|
|
||||||
}
|
|
||||||
|
|
||||||
propName = char.ToUpper(propName[0]) + propName.Substring(1);
|
|
||||||
var getStruct = new CodeMethodInvokeExpression(
|
|
||||||
new CodeMethodReferenceExpression(new CodeSnippetExpression("BlockEngine"),
|
|
||||||
"GetBlockInfo", new CodeTypeReference(type)),
|
|
||||||
new CodeThisReferenceExpression());
|
|
||||||
CodeExpression structFieldReference = new CodeFieldReferenceExpression(getStruct, field.Name);
|
|
||||||
CodeExpression reflectedGet = new CodeCastExpression(field.FieldType, new CodeMethodInvokeExpression(
|
|
||||||
new CodeMethodReferenceExpression(new CodeSnippetExpression("BlockEngine"),
|
|
||||||
"GetBlockInfo"),
|
|
||||||
new CodeThisReferenceExpression(), reflectedType, new CodePrimitiveExpression(field.Name)));
|
|
||||||
CodeExpression reflectedSet = new CodeMethodInvokeExpression(
|
|
||||||
new CodeMethodReferenceExpression(new CodeSnippetExpression("BlockEngine"),
|
|
||||||
"SetBlockInfo"),
|
|
||||||
new CodeThisReferenceExpression(), reflectedType, new CodePrimitiveExpression(field.Name),
|
|
||||||
new CodePropertySetValueReferenceExpression());
|
|
||||||
cl.Members.Add(new CodeMemberProperty
|
|
||||||
{
|
|
||||||
Name = propName,
|
|
||||||
HasGet = true,
|
|
||||||
HasSet = true,
|
|
||||||
GetStatements =
|
|
||||||
{
|
|
||||||
new CodeMethodReturnStatement(reflection ? reflectedGet : structFieldReference)
|
|
||||||
},
|
|
||||||
SetStatements =
|
|
||||||
{
|
|
||||||
reflection
|
|
||||||
? (CodeStatement)new CodeExpressionStatement(reflectedSet)
|
|
||||||
: new CodeAssignStatement(structFieldReference, new CodePropertySetValueReferenceExpression())
|
|
||||||
},
|
|
||||||
Type = new CodeTypeReference(field.FieldType),
|
|
||||||
Attributes = MemberAttributes.Public | MemberAttributes.Final,
|
|
||||||
Comments =
|
|
||||||
{
|
|
||||||
_start,
|
|
||||||
new CodeCommentStatement($"Gets or sets the {baseClass}'s {propName} property." +
|
|
||||||
$" {(attr != null ? "Tweakable stat." : "May not be saved.")}",
|
|
||||||
true),
|
|
||||||
_end
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly CodeCommentStatement _start = new CodeCommentStatement("<summary>", true);
|
|
||||||
private static readonly CodeCommentStatement _end = new CodeCommentStatement("</summary>", true);
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,53 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using HarmonyLib;
|
|
||||||
using RobocraftX.Blocks;
|
|
||||||
using RobocraftX.Common;
|
|
||||||
using RobocraftX.GroupTags;
|
|
||||||
using RobocraftX.PilotSeat;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Techblox.EngineBlock;
|
|
||||||
using Techblox.ServoBlocksServer;
|
|
||||||
using Techblox.WheelRigBlock;
|
|
||||||
|
|
||||||
namespace CodeGenerator
|
|
||||||
{
|
|
||||||
internal class Program
|
|
||||||
{
|
|
||||||
public static void Main(string[] args)
|
|
||||||
{
|
|
||||||
GenerateBlockClasses();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void GenerateBlockClasses()
|
|
||||||
{
|
|
||||||
var bcg = new BlockClassGenerator();
|
|
||||||
bcg.Generate("Engine", null, new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "engineOn", "On" }
|
|
||||||
}, AccessTools.TypeByName("Techblox.EngineBlock.EngineBlockComponent"), // Simulation time properties
|
|
||||||
typeof(EngineBlockTweakableComponent), typeof(EngineBlockReadonlyComponent));
|
|
||||||
bcg.Generate("DampedSpring", "DAMPEDSPRING_BLOCK_GROUP", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{"maxExtent", "MaxExtension"}
|
|
||||||
},
|
|
||||||
typeof(TweakableJointDampingComponent), typeof(DampedSpringReadOnlyStruct));
|
|
||||||
bcg.Generate("LogicGate", "LOGIC_BLOCK_GROUP");
|
|
||||||
bcg.Generate("Servo", types: typeof(ServoReadOnlyTweakableComponent), renames: new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{"minDeviation", "MinimumAngle"},
|
|
||||||
{"maxDeviation", "MaximumAngle"},
|
|
||||||
{"servoVelocity", "MaximumForce"}
|
|
||||||
});
|
|
||||||
bcg.Generate("WheelRig", "WHEELRIG_BLOCK_BUILD_GROUP", null,
|
|
||||||
typeof(WheelRigTweakableStruct), typeof(WheelRigReadOnlyStruct),
|
|
||||||
typeof(WheelRigSteerableTweakableStruct), typeof(WheelRigSteerableReadOnlyStruct));
|
|
||||||
bcg.Generate("Seat", "RobocraftX.PilotSeat.SeatGroups.PILOTSEAT_BLOCK_BUILD_GROUP", null, typeof(SeatFollowCamComponent), typeof(SeatReadOnlySettingsComponent));
|
|
||||||
bcg.Generate("Piston", null, new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{"pistonVelocity", "MaximumForce"}
|
|
||||||
}, typeof(PistonReadOnlyStruct));
|
|
||||||
bcg.Generate("Motor", null, null, typeof(MotorReadOnlyStruct));
|
|
||||||
//bcg.Generate("ObjectID", "ObjectIDBlockExclusiveGroups.OBJECT_ID_BLOCK_GROUP", null, typeof(ObjectIDTweakableComponent));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<packages>
|
|
||||||
<package id="Lib.Harmony" version="2.2.0" targetFramework="net472" />
|
|
||||||
</packages>
|
|
31
GamecraftModdingAPI.sln
Normal file
31
GamecraftModdingAPI.sln
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.29411.108
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GamecraftModdingAPI", "GamecraftModdingAPI\GamecraftModdingAPI.csproj", "{7FD5A7D8-4F3E-426A-B07D-7DC70442A4DF}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Automation", "Automation\Automation.csproj", "{1DF6E538-4DA4-4708-A567-781AF788921A}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|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
|
||||||
|
{1DF6E538-4DA4-4708-A567-781AF788921A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1DF6E538-4DA4-4708-A567-781AF788921A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1DF6E538-4DA4-4708-A567-781AF788921A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1DF6E538-4DA4-4708-A567-781AF788921A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {72FB94D0-6C50-475B-81E0-C94C7D7A2A17}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
20
GamecraftModdingAPI/Blocks/BlockColors.cs
Normal file
20
GamecraftModdingAPI/Blocks/BlockColors.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Preset block colours
|
||||||
|
/// </summary>
|
||||||
|
public enum BlockColors
|
||||||
|
{
|
||||||
|
Default = byte.MaxValue,
|
||||||
|
White = 0,
|
||||||
|
Pink,
|
||||||
|
Purple,
|
||||||
|
Blue,
|
||||||
|
Aqua,
|
||||||
|
Green,
|
||||||
|
Lime,
|
||||||
|
Yellow,
|
||||||
|
Orange,
|
||||||
|
Red
|
||||||
|
}
|
||||||
|
}
|
230
GamecraftModdingAPI/Blocks/BlockIDs.cs
Normal file
230
GamecraftModdingAPI/Blocks/BlockIDs.cs
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Possible block types
|
||||||
|
/// </summary>
|
||||||
|
public enum BlockIDs
|
||||||
|
{
|
||||||
|
AluminiumCube,
|
||||||
|
AxleS,
|
||||||
|
HingeS = 3,
|
||||||
|
MotorS,
|
||||||
|
HingeM,
|
||||||
|
MotorM,
|
||||||
|
TyreM,
|
||||||
|
AxleM,
|
||||||
|
IronCube,
|
||||||
|
RubberCube,
|
||||||
|
OiledCube,
|
||||||
|
AluminiumConeSegment, //12
|
||||||
|
AluminiumCorner,
|
||||||
|
AluminiumRoundedCorner,
|
||||||
|
AluminiumSlicedCube,
|
||||||
|
AluminiumRoundedSlicedCube,
|
||||||
|
AluminiumCylinder,
|
||||||
|
AluminiumPyramidSegment,
|
||||||
|
AluminiumSlope,
|
||||||
|
AluminiumRoundedSlope,
|
||||||
|
AluminiumSphere,
|
||||||
|
RubberConeSegment, //22
|
||||||
|
RubberCorner,
|
||||||
|
RubberRoundedCorner,
|
||||||
|
RubberSlicedCube,
|
||||||
|
RubberRoundedSlicedCube,
|
||||||
|
RubberCylinder,
|
||||||
|
RubberPyramidSegment,
|
||||||
|
RubberSlope,
|
||||||
|
RubberRoundedSlope,
|
||||||
|
RubberSphere,
|
||||||
|
OiledConeSegment, //32
|
||||||
|
OiledCorner,
|
||||||
|
OiledRoundedCorner,
|
||||||
|
OiledSlicedCube,
|
||||||
|
OiledRoundedSlicedCube,
|
||||||
|
OiledCylinder,
|
||||||
|
OiledPyramidSegment,
|
||||||
|
OiledSlope,
|
||||||
|
OiledRoundedSlope,
|
||||||
|
OiledSphere,
|
||||||
|
IronConeSegment, //42
|
||||||
|
IronCorner,
|
||||||
|
IronRoundedCorner,
|
||||||
|
IronSlicedCube,
|
||||||
|
IronRoundedSlicedCube,
|
||||||
|
IronCylinder,
|
||||||
|
IronPyramidSegment,
|
||||||
|
IronSlope,
|
||||||
|
IronRoundedSlope,
|
||||||
|
IronSphere,
|
||||||
|
GlassCube, //52
|
||||||
|
GlassSlicedCube,
|
||||||
|
GlassSlope,
|
||||||
|
GlassCorner,
|
||||||
|
GlassPyramidSegment,
|
||||||
|
GlassRoundedSlicedCube,
|
||||||
|
GlassRoundedSlope,
|
||||||
|
GlassRoundedCorner,
|
||||||
|
GlassConeSegment,
|
||||||
|
GlassCylinder,
|
||||||
|
GlassSphere,
|
||||||
|
Lever, //63 - two IDs skipped
|
||||||
|
PlayerSpawn = 66, //Crashes without special handling
|
||||||
|
SmallSpawn,
|
||||||
|
MediumSpawn,
|
||||||
|
LargeSpawn,
|
||||||
|
BallJoint,
|
||||||
|
UniversalJoint,
|
||||||
|
ServoAxle,
|
||||||
|
ServoHinge,
|
||||||
|
StepperAxle,
|
||||||
|
StepperHinge,
|
||||||
|
TelescopicJoint,
|
||||||
|
DampedSpring,
|
||||||
|
ServoPiston,
|
||||||
|
StepperPiston,
|
||||||
|
PneumaticPiston,
|
||||||
|
PneumaticHinge,
|
||||||
|
PneumaticAxle, //82
|
||||||
|
PilotSeat = 90, //Might crash
|
||||||
|
PassengerSeat,
|
||||||
|
PilotControls,
|
||||||
|
GrassCube,
|
||||||
|
DirtCube,
|
||||||
|
GrassConeSegment,
|
||||||
|
GrassCorner,
|
||||||
|
GrassRoundedCorner,
|
||||||
|
GrassSlicedCube,
|
||||||
|
GrassRoundedSlicedCube,
|
||||||
|
GrassPyramidSegment,
|
||||||
|
GrassSlope,
|
||||||
|
GrassRoundedSlope,
|
||||||
|
DirtConeSegment,
|
||||||
|
DirtCorner,
|
||||||
|
DirtRoundedCorner,
|
||||||
|
DirtSlicedCube,
|
||||||
|
DirtRoundedSlicedCube,
|
||||||
|
DirtPyramidSegment,
|
||||||
|
DirtSlope,
|
||||||
|
DirtRoundedSlope,
|
||||||
|
RubberHemisphere,
|
||||||
|
AluminiumHemisphere,
|
||||||
|
GrassInnerCornerBulged,
|
||||||
|
DirtInnerCornerBulged,
|
||||||
|
IronHemisphere,
|
||||||
|
OiledHemisphere,
|
||||||
|
GlassHemisphere,
|
||||||
|
TyreS,
|
||||||
|
ThreeWaySwitch,
|
||||||
|
Dial, //120
|
||||||
|
CharacterOnEnterTrigger, //Probably crashes
|
||||||
|
CharacterOnLeaveTrigger,
|
||||||
|
CharacterOnStayTrigger,
|
||||||
|
ObjectOnEnterTrigger,
|
||||||
|
ObjectOnLeaveTrigger,
|
||||||
|
ObjectOnStayTrigger,
|
||||||
|
Button,
|
||||||
|
Switch,
|
||||||
|
TextBlock, //Brings up a screen
|
||||||
|
ConsoleBlock, //Brings up a screen
|
||||||
|
Door,
|
||||||
|
GlassDoor,
|
||||||
|
PoweredDoor,
|
||||||
|
PoweredGlassDoor,
|
||||||
|
AluminiumTubeCorner,
|
||||||
|
IronTubeCorner,
|
||||||
|
WoodCube,
|
||||||
|
WoodSlicedCube,
|
||||||
|
WoodSlope,
|
||||||
|
WoodCorner,
|
||||||
|
WoodPyramidSegment,
|
||||||
|
WoodConeSegment,
|
||||||
|
WoodRoundedSlicedCube,
|
||||||
|
WoodRoundedSlope,
|
||||||
|
WoodRoundedCorner,
|
||||||
|
WoodCylinder,
|
||||||
|
WoodHemisphere,
|
||||||
|
WoodSphere,
|
||||||
|
BrickCube, //149
|
||||||
|
BrickSlicedCube = 151,
|
||||||
|
BrickSlope,
|
||||||
|
BrickCorner,
|
||||||
|
ConcreteCube,
|
||||||
|
ConcreteSlicedCube,
|
||||||
|
ConcreteSlope,
|
||||||
|
ConcreteCorner,
|
||||||
|
RoadCarTyre,
|
||||||
|
OffRoadCarTyre,
|
||||||
|
RacingCarTyre,
|
||||||
|
BicycleTyre,
|
||||||
|
FrontBikeTyre,
|
||||||
|
RearBikeTyre,
|
||||||
|
ChopperBikeTyre,
|
||||||
|
TractorTyre,
|
||||||
|
MonsterTruckTyre,
|
||||||
|
MotocrossBikeTyre,
|
||||||
|
CartTyre, //168
|
||||||
|
ObjectIdentifier,
|
||||||
|
ANDLogicBlock,
|
||||||
|
NANDLogicBlock,
|
||||||
|
NORLogicBlock,
|
||||||
|
NOTLogicBlock,
|
||||||
|
ORLogicBlock,
|
||||||
|
XNORLogicBlock,
|
||||||
|
XORLogicBlock,
|
||||||
|
AbsoluteMathsBlock,
|
||||||
|
AdderMathsBlock,
|
||||||
|
DividerMathsBlock,
|
||||||
|
SignMathsBlock, //180
|
||||||
|
MaxMathsBlock,
|
||||||
|
MinMathsBlock,
|
||||||
|
MultiplierMathsBlock,
|
||||||
|
SubtractorMathsBlock,
|
||||||
|
SimpleConnector,
|
||||||
|
MeanMathsBlock,
|
||||||
|
Bit,
|
||||||
|
Counter,
|
||||||
|
Timer,
|
||||||
|
ObjectFilter,
|
||||||
|
PlayerFilter,
|
||||||
|
TeamFilter,
|
||||||
|
Number2Text, //193
|
||||||
|
BeachTree1 = 200,
|
||||||
|
BeachTree2,
|
||||||
|
BeachTree3,
|
||||||
|
Rock1,
|
||||||
|
Rock2,
|
||||||
|
Rock3,
|
||||||
|
Rock4,
|
||||||
|
BirchTree1,
|
||||||
|
BirchTree2,
|
||||||
|
BirchTree3,
|
||||||
|
PineTree1,
|
||||||
|
PineTree2,
|
||||||
|
PineTree3,
|
||||||
|
Flower1,
|
||||||
|
Flower2,
|
||||||
|
Flower3,
|
||||||
|
Shrub1,
|
||||||
|
Shrub2,
|
||||||
|
Shrub3,
|
||||||
|
CliffCube,
|
||||||
|
CliffSlicedCorner,
|
||||||
|
CliffCornerA,
|
||||||
|
CliffCornerB,
|
||||||
|
CliffSlopeA,
|
||||||
|
CliffSlopeB,
|
||||||
|
GrassEdge,
|
||||||
|
GrassEdgeInnerCorner,
|
||||||
|
GrassEdgeCorner,
|
||||||
|
GrassEdgeSlope,
|
||||||
|
CentreHUD,
|
||||||
|
ObjectiveHUD,
|
||||||
|
GameStatsHUD, //231
|
||||||
|
Mover = 250,
|
||||||
|
Rotator,
|
||||||
|
MovementDampener,
|
||||||
|
RotationDampener,
|
||||||
|
AdvancedMover,
|
||||||
|
AdvancedRotator
|
||||||
|
}
|
||||||
|
}
|
49
GamecraftModdingAPI/Blocks/BlockIdentifiers.cs
Normal file
49
GamecraftModdingAPI/Blocks/BlockIdentifiers.cs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using Svelto.ECS;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
|
||||||
|
using Harmony;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ExclusiveGroups and IDs used with blocks
|
||||||
|
/// </summary>
|
||||||
|
public static class BlockIdentifiers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Blocks placed by the player
|
||||||
|
/// </summary>
|
||||||
|
public static ExclusiveGroup OWNED_BLOCKS { get { return CommonExclusiveGroups.OWNED_BLOCKS_GROUP; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extra parts used in functional blocks
|
||||||
|
/// </summary>
|
||||||
|
public static ExclusiveGroup FUNCTIONAL_BLOCK_PARTS { get { return CommonExclusiveGroups.FUNCTIONAL_BLOCK_PART_GROUP; } }
|
||||||
|
|
||||||
|
/// <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 SPAWN_POINTS { get { return CommonExclusiveGroups.SPAWN_POINTS_GROUP; } }
|
||||||
|
|
||||||
|
public static ExclusiveGroup SPAWN_POINTS_DISABLED { get { return CommonExclusiveGroups.SPAWN_POINTS_DISABLED_GROUP; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of the most recently placed block
|
||||||
|
/// </summary>
|
||||||
|
public static uint LatestBlockID {
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ((uint) AccessTools.Field(typeof(CommonExclusiveGroups), "_nextBlockEntityID").GetValue(null)) - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
GamecraftModdingAPI/Blocks/BlockUtility.cs
Normal file
31
GamecraftModdingAPI/Blocks/BlockUtility.cs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
using RobocraftX.Blocks.Ghost;
|
||||||
|
using RobocraftX.Character.Camera;
|
||||||
|
using RobocraftX.Character.Factories;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
public class BlockUtility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the block the player is currently looking at.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="playerId">The player's ID</param>
|
||||||
|
/// <param name="entitiesDB">The entities DB</param>
|
||||||
|
/// <param name="maxDistance">The maximum distance from the player (default is the player's building reach)</param>
|
||||||
|
/// <returns>The block's EGID or null if not found</returns>
|
||||||
|
public static EGID? GetBlockLookedAt(uint playerId, EntitiesDB entitiesDB, float maxDistance = -1f)
|
||||||
|
{
|
||||||
|
if (!entitiesDB.TryQueryMappedEntities<CharacterCameraRayCastEntityStruct>(
|
||||||
|
CameraExclusiveGroups.CameraGroup, out var mapper))
|
||||||
|
return null;
|
||||||
|
mapper.TryGetEntity(playerId, out CharacterCameraRayCastEntityStruct rayCast);
|
||||||
|
float distance = maxDistance < 0
|
||||||
|
? GhostBlockUtils.GetBuildInteractionDistance(entitiesDB, rayCast)
|
||||||
|
: maxDistance;
|
||||||
|
if (rayCast.hit && rayCast.distance <= distance)
|
||||||
|
return rayCast.hitEgid;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
61
GamecraftModdingAPI/Blocks/Movement.cs
Normal file
61
GamecraftModdingAPI/Blocks/Movement.cs
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Unity.Mathematics;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Common block movement operations.
|
||||||
|
/// The functionality of this class only works in build mode.
|
||||||
|
/// </summary>
|
||||||
|
public static class Movement
|
||||||
|
{
|
||||||
|
private static MovementEngine movementEngine = new MovementEngine();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Move a single block by a specific (x,y,z) amount (offset).
|
||||||
|
/// The moved block will remain connected to the blocks it was touching before it was moved.
|
||||||
|
/// The block's placement grid and collision box are also moved.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The block's id</param>
|
||||||
|
/// <param name="vector">The movement amount (x,y,z)</param>
|
||||||
|
/// <returns>Whether the operation was successful</returns>
|
||||||
|
public static bool MoveBlock(uint id, float3 vector)
|
||||||
|
{
|
||||||
|
if (movementEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsBuildMode())
|
||||||
|
{
|
||||||
|
movementEngine.MoveBlock(id, vector);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Move all connected blocks by a specific (x,y,z) amount (offset).
|
||||||
|
/// The moved blocks will remain connected to the block they're touching.
|
||||||
|
/// All of the block's placement grids and collision boxes are also moved.
|
||||||
|
/// This is equivalent to calling MoveBlock() for every connected block.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The starting block's id</param>
|
||||||
|
/// <param name="vector">The movement amount (x,y,z)</param>
|
||||||
|
/// <returns>Whether the operation was successful</returns>
|
||||||
|
public static bool MoveConnectedBlocks(uint id, float3 vector)
|
||||||
|
{
|
||||||
|
if (movementEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsBuildMode())
|
||||||
|
{
|
||||||
|
movementEngine.MoveConnectedBlocks(id, vector);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
GamecraftModdingAPI.Utility.GameEngineManager.AddGameEngine(movementEngine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
83
GamecraftModdingAPI/Blocks/MovementEngine.cs
Normal file
83
GamecraftModdingAPI/Blocks/MovementEngine.cs
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using RobocraftX;
|
||||||
|
using RobocraftX.Blocks;
|
||||||
|
using RobocraftX.Blocks.Ghost;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.Multiplayer;
|
||||||
|
using RobocraftX.SimulationModeState;
|
||||||
|
using RobocraftX.UECS;
|
||||||
|
using Unity.Entities;
|
||||||
|
using Svelto.Context;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Svelto.ECS.EntityStructs;
|
||||||
|
using Unity.Transforms;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
using Svelto.DataStructures;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Engine which executes block movement actions
|
||||||
|
/// </summary>
|
||||||
|
public class MovementEngine : IApiEngine
|
||||||
|
{
|
||||||
|
public string Name { get; } = "GamecraftModdingAPIMovementGameEngine";
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public bool IsInGame = false;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
IsInGame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
IsInGame = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// implementations for Movement static class
|
||||||
|
|
||||||
|
public float3 MoveBlock(uint blockID, 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);
|
||||||
|
// main (persistent) position
|
||||||
|
posStruct.position += vector;
|
||||||
|
// placement grid position
|
||||||
|
gridStruct.position += vector;
|
||||||
|
// rendered position
|
||||||
|
transStruct.position += vector;
|
||||||
|
// collision position
|
||||||
|
FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.uecsEntity, new Translation
|
||||||
|
{
|
||||||
|
Value = posStruct.position
|
||||||
|
});
|
||||||
|
return posStruct.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float3 MoveConnectedBlocks(uint blockID, float3 vector)
|
||||||
|
{
|
||||||
|
Stack<uint> cubeStack = new Stack<uint>();
|
||||||
|
FasterList<uint> cubesToMove = new FasterList<uint>();
|
||||||
|
ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubeStack, cubesToMove, (in GridConnectionsEntityStruct g) => { return false; });
|
||||||
|
for (int i = 0; i < cubesToMove.count; i++)
|
||||||
|
{
|
||||||
|
MoveBlock(cubesToMove[i], vector);
|
||||||
|
entitiesDB.QueryEntity<GridConnectionsEntityStruct>(cubesToMove[i], CommonExclusiveGroups.OWNED_BLOCKS_GROUP).isProcessed = false;
|
||||||
|
}
|
||||||
|
return this.entitiesDB.QueryEntity<PositionEntityStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP).position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
GamecraftModdingAPI/Blocks/Placement.cs
Normal file
55
GamecraftModdingAPI/Blocks/Placement.cs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using Unity.Mathematics;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Common block placement operations.
|
||||||
|
/// The functionality in this class is for build mode.
|
||||||
|
/// </summary>
|
||||||
|
public static class Placement
|
||||||
|
{
|
||||||
|
private static PlacementEngine placementEngine = new PlacementEngine();
|
||||||
|
|
||||||
|
/// <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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="block">The block's type</param>
|
||||||
|
/// <param name="color">The block's color</param>
|
||||||
|
/// <param name="darkness">The block color's darkness (0-9) - 0 is default color</param>
|
||||||
|
/// <param name="position">The block's position in the grid - default block size is 0.2</param>
|
||||||
|
/// <param name="rotation">The block's rotation in degrees</param>
|
||||||
|
/// <param name="uscale">The block's uniform scale - default scale is 1 (with 0.2 width)</param>
|
||||||
|
/// <param name="scale">The block's non-uniform scale - 0 means <paramref name="uscale"/> is used</param>
|
||||||
|
/// <param name="playerId">The player who placed the block</param>
|
||||||
|
/// <returns>The placed block's ID or null if failed</returns>
|
||||||
|
public static EGID? PlaceBlock(BlockIDs block, float3 position,
|
||||||
|
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0,
|
||||||
|
int uscale = 1, float3 scale = default, uint playerId = 0)
|
||||||
|
{
|
||||||
|
if (placementEngine.IsInGame && GameState.IsBuildMode())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return placementEngine.PlaceBlock(block, color, darkness, position, uscale, scale, playerId, rotation);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logging.MetaDebugLog(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
GameEngineManager.AddGameEngine(placementEngine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
146
GamecraftModdingAPI/Blocks/PlacementEngine.cs
Normal file
146
GamecraftModdingAPI/Blocks/PlacementEngine.cs
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using DataLoader;
|
||||||
|
using Harmony;
|
||||||
|
using RobocraftX.Blocks;
|
||||||
|
using RobocraftX.Blocks.Ghost;
|
||||||
|
using RobocraftX.Blocks.Scaling;
|
||||||
|
using RobocraftX.Character;
|
||||||
|
using RobocraftX.CommandLine.Custom;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.Common.Input;
|
||||||
|
using RobocraftX.Common.Utilities;
|
||||||
|
using RobocraftX.CR.MachineEditing;
|
||||||
|
using RobocraftX.StateSync;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Svelto.ECS.EntityStructs;
|
||||||
|
using Unity.Jobs;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
using UnityEngine;
|
||||||
|
using uREPL;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Engine which executes block placement actions
|
||||||
|
/// </summary>
|
||||||
|
public class PlacementEngine : IApiEngine
|
||||||
|
{
|
||||||
|
public bool IsInGame = false;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
IsInGame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
IsInGame = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { get; set; }
|
||||||
|
private static BlockEntityFactory _blockEntityFactory; //Injected from PlaceBlockEngine
|
||||||
|
|
||||||
|
public EGID PlaceBlock(BlockIDs block, BlockColors color, byte darkness, float3 position, int uscale,
|
||||||
|
float3 scale, uint playerId, float3 rotation)
|
||||||
|
{ //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, playerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EGID 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.");
|
||||||
|
if (uscale < 1)
|
||||||
|
throw new Exception("Scale needs to be at least 1");
|
||||||
|
if (scale.x < 4e-5) scale.x = uscale;
|
||||||
|
if (scale.y < 4e-5) scale.y = uscale;
|
||||||
|
if (scale.z < 4e-5) scale.z = uscale;
|
||||||
|
uint dbid = block;
|
||||||
|
if (!PrefabsID.DBIDMAP.ContainsKey(dbid))
|
||||||
|
throw new Exception("Block with ID " + dbid + " not found!");
|
||||||
|
//RobocraftX.CR.MachineEditing.PlaceBlockEngine
|
||||||
|
ScalingEntityStruct scaling = new ScalingEntityStruct {scale = scale};
|
||||||
|
Quaternion rotQ = Quaternion.Euler(rot);
|
||||||
|
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
|
||||||
|
{
|
||||||
|
blockPlacementHeight = uscale, blockPlacementWidth = uscale, desiredScaleFactor = uscale,
|
||||||
|
snapGridScale = uscale,
|
||||||
|
unitSnapOffset = 0, isUsingUnitSize = true
|
||||||
|
};
|
||||||
|
EquippedColourStruct colour = new EquippedColourStruct {indexInPalette = color};
|
||||||
|
EGID newBlockID;
|
||||||
|
switch (category.category)
|
||||||
|
{
|
||||||
|
case CubeCategory.SpawnPoint:
|
||||||
|
case CubeCategory.BuildingSpawnPoint:
|
||||||
|
newBlockID = MachineEditingGroups.NewSpawnPointBlockID;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
newBlockID = MachineEditingGroups.NewBlockID;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityComponentInitializer
|
||||||
|
structInitializer =
|
||||||
|
_blockEntityFactory.Build(newBlockID, dbid); //The ghost block index is only used for triggers
|
||||||
|
if (colour.indexInPalette != byte.MaxValue)
|
||||||
|
structInitializer.Init(new ColourParameterEntityStruct
|
||||||
|
{
|
||||||
|
indexInPalette = colour.indexInPalette,
|
||||||
|
needsUpdate = true
|
||||||
|
});
|
||||||
|
uint prefabId = PrefabsID.GetPrefabId(dbid, 0);
|
||||||
|
structInitializer.Init(new GFXPrefabEntityStructGPUI(prefabId));
|
||||||
|
structInitializer.Init(new PhysicsPrefabEntityStruct(prefabId));
|
||||||
|
structInitializer.Init(dbEntity);
|
||||||
|
structInitializer.Init(new PositionEntityStruct {position = position});
|
||||||
|
structInitializer.Init(rotation);
|
||||||
|
structInitializer.Init(scaling);
|
||||||
|
structInitializer.Init(gridRotation);
|
||||||
|
structInitializer.Init(new UniformBlockScaleEntityStruct
|
||||||
|
{
|
||||||
|
scaleFactor = placementScale.desiredScaleFactor
|
||||||
|
});
|
||||||
|
structInitializer.Init(new BlockPlacementInfoStruct()
|
||||||
|
{
|
||||||
|
loadedFromDisk = false,
|
||||||
|
placedBy = playerId
|
||||||
|
});
|
||||||
|
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.placedBlockWasAPickedBlock = false;
|
||||||
|
return newBlockID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; } = "GamecraftModdingAPIPlacementGameEngine";
|
||||||
|
|
||||||
|
[HarmonyPatch]
|
||||||
|
public class FactoryObtainerPatch
|
||||||
|
{
|
||||||
|
static void Postfix(BlockEntityFactory blockEntityFactory)
|
||||||
|
{
|
||||||
|
_blockEntityFactory = blockEntityFactory;
|
||||||
|
Logging.MetaDebugLog("Block entity factory injected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static MethodBase TargetMethod(HarmonyInstance instance)
|
||||||
|
{
|
||||||
|
return AccessTools.TypeByName("RobocraftX.CR.MachineEditing.PlaceBlockEngine").GetConstructors()[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
GamecraftModdingAPI/Blocks/Removal.cs
Normal file
28
GamecraftModdingAPI/Blocks/Removal.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
public class Removal
|
||||||
|
{
|
||||||
|
private static RemovalEngine _removalEngine = new RemovalEngine();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the block with the given ID. Returns false if the block doesn't exist or the game isn't in build mode.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetBlock">The block to remove</param>
|
||||||
|
/// <returns>Whether the block was successfully removed</returns>
|
||||||
|
public static bool RemoveBlock(EGID targetBlock)
|
||||||
|
{
|
||||||
|
if (GameState.IsBuildMode())
|
||||||
|
return _removalEngine.RemoveBlock(targetBlock);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
GameEngineManager.AddGameEngine(_removalEngine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
74
GamecraftModdingAPI/Blocks/RemovalEngine.cs
Normal file
74
GamecraftModdingAPI/Blocks/RemovalEngine.cs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using Harmony;
|
||||||
|
using RobocraftX.Blocks;
|
||||||
|
using RobocraftX.Blocks.Ghost;
|
||||||
|
using RobocraftX.Character.Camera;
|
||||||
|
using RobocraftX.Character.Factories;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.Players;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using uREPL;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Commands;
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
public class RemovalEngine : IApiEngine
|
||||||
|
{
|
||||||
|
private static IEntityFunctions _entityFunctions;
|
||||||
|
private static MachineGraphConnectionEntityFactory _connectionFactory;
|
||||||
|
|
||||||
|
public bool RemoveBlock(EGID target)
|
||||||
|
{
|
||||||
|
if (!entitiesDB.Exists<MachineGraphConnectionsEntityStruct>(target))
|
||||||
|
return false;
|
||||||
|
var connections = entitiesDB.QueryEntity<MachineGraphConnectionsEntityStruct>(target);
|
||||||
|
for (int i = connections.connections.Length - 1; i >= 0; i--)
|
||||||
|
_connectionFactory.RemoveConnection(connections, i, entitiesDB);
|
||||||
|
_entityFunctions.RemoveEntity<BlockEntityDescriptor>(target);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
/*CommandManager.AddCommand(new SimpleCustomCommandEngine(() =>
|
||||||
|
{
|
||||||
|
var block = BlockUtility.GetBlockLookedAt(LocalPlayerIDUtility.GetLocalPlayerID(entitiesDB), entitiesDB);
|
||||||
|
if (block.HasValue)
|
||||||
|
{
|
||||||
|
RemoveBlock(block.Value);
|
||||||
|
Log.Output("Removed block.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Log.Output("No block found where you're looking at.");
|
||||||
|
}, "removeCube", "Removes the cube you're looking at."));*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { get; set; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; } = "GamecraftModdingAPIRemovalGameEngine";
|
||||||
|
|
||||||
|
[HarmonyPatch]
|
||||||
|
public class FactoryObtainerPatch
|
||||||
|
{
|
||||||
|
static void Postfix(IEntityFunctions entityFunctions,
|
||||||
|
MachineGraphConnectionEntityFactory machineGraphConnectionEntityFactory)
|
||||||
|
{
|
||||||
|
_entityFunctions = entityFunctions;
|
||||||
|
_connectionFactory = machineGraphConnectionEntityFactory;
|
||||||
|
Logging.MetaDebugLog("Requirements injected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static MethodBase TargetMethod(HarmonyInstance instance)
|
||||||
|
{
|
||||||
|
return AccessTools.TypeByName("RobocraftX.CR.MachineEditing.RemoveBlockEngine").GetConstructors()[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
GamecraftModdingAPI/Blocks/Rotation.cs
Normal file
59
GamecraftModdingAPI/Blocks/Rotation.cs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Unity.Mathematics;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Common block rotation operations.
|
||||||
|
/// The functionality in this class is not completely implemented and will only work in build mode.
|
||||||
|
/// </summary>
|
||||||
|
public static class Rotation
|
||||||
|
{
|
||||||
|
private static RotationEngine rotationEngine = new RotationEngine();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotate a single block by a specific amount in degrees.
|
||||||
|
/// This not destroy inter-block connections, so neighbouring blocks will remain attached despite appearances.
|
||||||
|
/// The cube placement grid and collision are also rotated.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The block's id</param>
|
||||||
|
/// <param name="vector">The rotation amount around the x,y,z-axis</param>
|
||||||
|
/// <returns>Whether the operation was successful</returns>
|
||||||
|
public static bool RotateBlock(uint id, float3 vector)
|
||||||
|
{
|
||||||
|
if (rotationEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsBuildMode())
|
||||||
|
{
|
||||||
|
rotationEngine.RotateBlock(id, vector);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotate all connected blocks by a specific amount in degrees.
|
||||||
|
/// This does not do anything because it has not been implemented.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The starting block's id</param>
|
||||||
|
/// <param name="vector">The rotation around the x,y,z-axis</param>
|
||||||
|
/// <returns>Whether the operation was successful</returns>
|
||||||
|
public static bool RotateConnectedBlocks(uint id, float3 vector)
|
||||||
|
{
|
||||||
|
if (rotationEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsBuildMode())
|
||||||
|
{
|
||||||
|
rotationEngine.RotateConnectedBlocks(id, vector);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
GamecraftModdingAPI.Utility.GameEngineManager.AddGameEngine(rotationEngine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
GamecraftModdingAPI/Blocks/RotationEngine.cs
Normal file
82
GamecraftModdingAPI/Blocks/RotationEngine.cs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using RobocraftX;
|
||||||
|
using RobocraftX.Blocks;
|
||||||
|
using RobocraftX.Blocks.Ghost;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.Multiplayer;
|
||||||
|
using RobocraftX.SimulationModeState;
|
||||||
|
using RobocraftX.UECS;
|
||||||
|
using Unity.Entities;
|
||||||
|
using Svelto.Context;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Svelto.ECS.EntityStructs;
|
||||||
|
using Unity.Transforms;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Engine which executes block movement actions
|
||||||
|
/// </summary>
|
||||||
|
public class RotationEngine : IApiEngine
|
||||||
|
{
|
||||||
|
public string Name { get; } = "GamecraftModdingAPIRotationGameEngine";
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public bool IsInGame = false;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
IsInGame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
IsInGame = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// implementations for Rotation static class
|
||||||
|
|
||||||
|
public float3 RotateBlock(uint blockID, 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);
|
||||||
|
// main (persistent) position
|
||||||
|
Quaternion newRotation = (Quaternion)rotStruct.rotation;
|
||||||
|
newRotation.eulerAngles += vector;
|
||||||
|
rotStruct.rotation = (quaternion)newRotation;
|
||||||
|
// placement grid rotation
|
||||||
|
Quaternion newGridRotation = (Quaternion)gridStruct.rotation;
|
||||||
|
newGridRotation.eulerAngles += vector;
|
||||||
|
gridStruct.rotation = (quaternion)newGridRotation;
|
||||||
|
// rendered position
|
||||||
|
Quaternion newTransRotation = (Quaternion)rotStruct.rotation;
|
||||||
|
newTransRotation.eulerAngles += vector;
|
||||||
|
transStruct.rotation = newTransRotation;
|
||||||
|
// collision position
|
||||||
|
FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.uecsEntity, new Unity.Transforms.Rotation
|
||||||
|
{
|
||||||
|
Value = rotStruct.rotation
|
||||||
|
});
|
||||||
|
return ((Quaternion)rotStruct.rotation).eulerAngles;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public float3 RotateConnectedBlocks(uint blockID, Vector3 vector)
|
||||||
|
{
|
||||||
|
// TODO: Implement and figure out the math
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
163
GamecraftModdingAPI/Blocks/SignalEngine.cs
Normal file
163
GamecraftModdingAPI/Blocks/SignalEngine.cs
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using RobocraftX;
|
||||||
|
using RobocraftX.Blocks;
|
||||||
|
using RobocraftX.Blocks.Ghost;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.Multiplayer;
|
||||||
|
using RobocraftX.SimulationModeState;
|
||||||
|
using RobocraftX.UECS;
|
||||||
|
using Unity.Entities;
|
||||||
|
using Svelto.Context;
|
||||||
|
using Svelto.DataStructures;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Svelto.ECS.EntityStructs;
|
||||||
|
using Unity.Transforms;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
using UnityEngine;
|
||||||
|
using Gamecraft.Wires;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Engine which executes signal actions
|
||||||
|
/// </summary>
|
||||||
|
public class SignalEngine : IApiEngine
|
||||||
|
{
|
||||||
|
public string Name { get; } = "GamecraftModdingAPISignalGameEngine";
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public bool IsInGame = false;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
IsInGame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
IsInGame = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// implementations for Signal static class
|
||||||
|
|
||||||
|
public bool SetSignal(EGID blockID, float signal, out uint signalID, bool input = true)
|
||||||
|
{
|
||||||
|
signalID = GetSignalIDs(blockID, input)[0];
|
||||||
|
return SetSignal(signalID, signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SetSignal(uint signalID, float signal, bool input = true)
|
||||||
|
{
|
||||||
|
var array = GetSignalStruct(signalID, out uint index, input);
|
||||||
|
if (array != null) array[index].valueAsFloat = signal;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float AddSignal(EGID blockID, float signal, out uint signalID, bool clamp = true, bool input = true)
|
||||||
|
{
|
||||||
|
signalID = GetSignalIDs(blockID, input)[0];
|
||||||
|
return AddSignal(signalID, signal, clamp, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float AddSignal(uint signalID, float signal, bool clamp = true, bool input = true)
|
||||||
|
{
|
||||||
|
var array = GetSignalStruct(signalID, out uint index, input);
|
||||||
|
if (array != null)
|
||||||
|
{
|
||||||
|
ref var channelData = ref array[index];
|
||||||
|
channelData.valueAsFloat += signal;
|
||||||
|
if (clamp)
|
||||||
|
{
|
||||||
|
if (channelData.valueAsFloat > Signals.POSITIVE_HIGH)
|
||||||
|
{
|
||||||
|
channelData.valueAsFloat = Signals.POSITIVE_HIGH;
|
||||||
|
}
|
||||||
|
else if (channelData.valueAsFloat < Signals.NEGATIVE_HIGH)
|
||||||
|
{
|
||||||
|
channelData.valueAsFloat = Signals.NEGATIVE_HIGH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return channelData.valueAsFloat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return signal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetSignal(EGID blockID, out uint signalID, bool input = true)
|
||||||
|
{
|
||||||
|
signalID = GetSignalIDs(blockID, input)[0];
|
||||||
|
return GetSignal(signalID, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetSignal(uint signalID, bool input = true)
|
||||||
|
{
|
||||||
|
var array = GetSignalStruct(signalID, out uint index, input);
|
||||||
|
return array?[index].valueAsFloat ?? 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint[] GetSignalIDs(EGID blockID, bool input = true)
|
||||||
|
{
|
||||||
|
ref BlockPortsStruct bps = ref entitiesDB.QueryEntity<BlockPortsStruct>(blockID);
|
||||||
|
uint[] signals;
|
||||||
|
if (input) {
|
||||||
|
signals = new uint[bps.inputCount];
|
||||||
|
for (uint i = 0u; i < bps.inputCount; i++)
|
||||||
|
{
|
||||||
|
signals[i] = bps.firstInputID + i;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
signals = new uint[bps.outputCount];
|
||||||
|
for (uint i = 0u; i < bps.outputCount; i++)
|
||||||
|
{
|
||||||
|
signals[i] = bps.firstOutputID + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return signals;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ChannelDataStruct[] GetSignalStruct(uint signalID, out uint index, bool input = true)
|
||||||
|
{
|
||||||
|
ExclusiveGroup group = input
|
||||||
|
? NamedExclusiveGroup<InputPortsGroup>.Group
|
||||||
|
: NamedExclusiveGroup<OutputPortsGroup>.Group;
|
||||||
|
if (entitiesDB.Exists<PortEntityStruct>(signalID, group))
|
||||||
|
{
|
||||||
|
index = entitiesDB.QueryEntity<PortEntityStruct>(signalID, group).anyChannelIndex;
|
||||||
|
ChannelDataStruct[] channelData = entitiesDB
|
||||||
|
.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<ChannelDataGroup>.Group)
|
||||||
|
.ToFastAccess(out uint _);
|
||||||
|
return channelData;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = 0;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
183
GamecraftModdingAPI/Blocks/Signals.cs
Normal file
183
GamecraftModdingAPI/Blocks/Signals.cs
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// [EXPERIMENTAL] Common block signal operations
|
||||||
|
/// The functionality in this class only works when in a game.
|
||||||
|
/// </summary>
|
||||||
|
public static class Signals
|
||||||
|
{
|
||||||
|
// Signal constants
|
||||||
|
public static readonly float HIGH = 1.0f;
|
||||||
|
public static readonly float POSITIVE_HIGH = HIGH;
|
||||||
|
public static readonly float NEGATIVE_HIGH = -1.0f;
|
||||||
|
public static readonly float LOW = 0.0f;
|
||||||
|
|
||||||
|
private static SignalEngine signalEngine = new SignalEngine();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the electric block's (first) signal value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="blockID">The block's id.</param>
|
||||||
|
/// <param name="signal">The signal value (-1 to 1; not enforced).</param>
|
||||||
|
/// <param name="input">Whether to retrieve input IDs (true) or output IDs (false).</param>
|
||||||
|
/// <param name="owned">Whether the block is in the owned group (true) or functional group (false)</param>
|
||||||
|
public static void SetSignalByBlock(uint blockID, float signal, bool input = true, bool owned = true)
|
||||||
|
{
|
||||||
|
EGID egid = new EGID(blockID, owned ? BlockIdentifiers.OWNED_BLOCKS : BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS);
|
||||||
|
if (signalEngine.IsInGame && GameState.IsSimulationMode())
|
||||||
|
{
|
||||||
|
signalEngine.SetSignal(egid, signal, out uint _, input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetSignalByBlock(EGID blockID, float signal, bool input = true)
|
||||||
|
{
|
||||||
|
if (signalEngine.IsInGame && GameState.IsSimulationMode())
|
||||||
|
{
|
||||||
|
signalEngine.SetSignal(blockID, signal, out uint _, input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the signal's value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="signalID">The channel cluster's id.</param>
|
||||||
|
/// <param name="signal">The signal value (-1 to 1; not enforced).</param>
|
||||||
|
/// <param name="input">Whether to retrieve input IDs (true) or output IDs (false).</param>
|
||||||
|
public static void SetSignalByID(uint signalID, float signal, bool input = true)
|
||||||
|
{
|
||||||
|
if (signalEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsSimulationMode())
|
||||||
|
{
|
||||||
|
signalEngine.SetSignal(signalID, signal, input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a value to an electric block's signal.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="blockID">The block's id.</param>
|
||||||
|
/// <param name="signal">The signal value to add.</param>
|
||||||
|
/// <param name="clamp">Whether to clamp the resulting signal value between -1 and 1.</param>
|
||||||
|
/// <param name="input">Whether to retrieve input IDs (true) or output IDs (false).</param>
|
||||||
|
/// <param name="owned">Whether the block is in the owned group (true) or functional group (false)</param>
|
||||||
|
/// <returns>The signal's new value.</returns>
|
||||||
|
public static float AddSignalByBlock(uint blockID, float signal, bool clamp = true, bool input = true, bool owned = true)
|
||||||
|
{
|
||||||
|
EGID egid = new EGID(blockID, owned ? BlockIdentifiers.OWNED_BLOCKS : BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS);
|
||||||
|
if (signalEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsSimulationMode())
|
||||||
|
{
|
||||||
|
return signalEngine.AddSignal(egid, signal, out uint _, clamp, input);
|
||||||
|
}
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float AddSignalByBlock(EGID blockID, float signal, bool clamp = true, bool input = true)
|
||||||
|
{
|
||||||
|
if (signalEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsSimulationMode())
|
||||||
|
{
|
||||||
|
return signalEngine.AddSignal(blockID, signal, out uint _, clamp, input);
|
||||||
|
}
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a value to a conductive cluster channel.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="signalID">The channel cluster's id.</param>
|
||||||
|
/// <param name="signal">The signal value to add.</param>
|
||||||
|
/// <param name="clamp">Whether to clamp the resulting signal value between -1 and 1.</param>
|
||||||
|
/// <param name="input">Whether to retrieve input IDs (true) or output IDs (false).</param>
|
||||||
|
/// <returns>The signal's new value.</returns>
|
||||||
|
public static float AddSignalByID(uint signalID, float signal, bool clamp = true, bool input = true)
|
||||||
|
{
|
||||||
|
if (signalEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsSimulationMode())
|
||||||
|
{
|
||||||
|
return signalEngine.AddSignal(signalID, signal, clamp, input);
|
||||||
|
}
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a electric block's signal's (first) value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="blockID">The block's id.</param>
|
||||||
|
/// <param name="input">Whether to retrieve input IDs (true) or output IDs (false).</param>
|
||||||
|
/// <param name="owned">Whether the block is in the owned group (true) or functional group (false)</param>
|
||||||
|
/// <returns>The signal's value.</returns>
|
||||||
|
public static float GetSignalByBlock(uint blockID, bool input = true, bool owned = true)
|
||||||
|
{
|
||||||
|
EGID egid = new EGID(blockID, owned? BlockIdentifiers.OWNED_BLOCKS : BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS);
|
||||||
|
if (signalEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsSimulationMode())
|
||||||
|
{
|
||||||
|
return signalEngine.GetSignal(egid, out uint _, input);
|
||||||
|
}
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float GetSignalByBlock(EGID blockID, bool input = true)
|
||||||
|
{
|
||||||
|
if (signalEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsSimulationMode())
|
||||||
|
{
|
||||||
|
return signalEngine.GetSignal(blockID, out uint _, input);
|
||||||
|
}
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a signal's value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="signalID">The signal's id.</param>
|
||||||
|
/// <param name="input">Whether to retrieve input IDs (true) or output IDs (false).</param>
|
||||||
|
/// <returns>The signal's value.</returns>
|
||||||
|
public static float GetSignalByID(uint signalID, bool input = true)
|
||||||
|
{
|
||||||
|
if (signalEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsSimulationMode())
|
||||||
|
{
|
||||||
|
return signalEngine.GetSignal(signalID, input);
|
||||||
|
}
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the ID of every electric block in the game world.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The block IDs.</returns>
|
||||||
|
public static EGID[] GetElectricBlocks()
|
||||||
|
{
|
||||||
|
return signalEngine.GetElectricBlocks();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the unique identifiers for the input wires connected to an electric block.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="blockID">The block's id.</param>
|
||||||
|
/// <param name="input">Whether to retrieve input IDs (true) or output IDs (false).</param>
|
||||||
|
/// <param name="owned">Whether the block is in the owned group (true) or functional group (false)</param>
|
||||||
|
/// <returns>The unique IDs.</returns>
|
||||||
|
public static uint[] GetSignalIDs(uint blockID, bool input = true, bool owned = true)
|
||||||
|
{
|
||||||
|
EGID egid = new EGID(blockID, owned ? BlockIdentifiers.OWNED_BLOCKS : BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS);
|
||||||
|
return signalEngine.GetSignalIDs(egid, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint[] GetSignalIDs(EGID blockID, bool input = true, bool owned = true)
|
||||||
|
{
|
||||||
|
return signalEngine.GetSignalIDs(blockID, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
GameEngineManager.AddGameEngine(signalEngine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
102
GamecraftModdingAPI/Blocks/Tweakable.cs
Normal file
102
GamecraftModdingAPI/Blocks/Tweakable.cs
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Common tweakable stats operations.
|
||||||
|
/// The functionality of this class works best in build mode.
|
||||||
|
/// </summary>
|
||||||
|
public static class Tweakable
|
||||||
|
{
|
||||||
|
private static TweakableEngine tweakableEngine = new TweakableEngine();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the tweakable stat's value using a dynamic variable type.
|
||||||
|
/// This is similar to GetStat<T> but without strong type enforcement.
|
||||||
|
/// This should be used in dynamically-typed languages like Python.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The stat's value.</returns>
|
||||||
|
/// <param name="blockID">The block's id.</param>
|
||||||
|
/// <param name="stat">The stat's enumerated id.</param>
|
||||||
|
public static dynamic GetStatD(uint blockID, TweakableStat stat)
|
||||||
|
{
|
||||||
|
return tweakableEngine.GetStatDynamic(blockID, stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the tweakable stat's value.
|
||||||
|
/// If T is not the same type as the stat, an InvalidCastException will be thrown.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The stat's value.</returns>
|
||||||
|
/// <param name="blockID">The block's id.</param>
|
||||||
|
/// <param name="stat">The stat's enumerated id.</param>
|
||||||
|
/// <typeparam name="T">The stat's type.</typeparam>
|
||||||
|
public static T GetStat<T>(uint blockID, TweakableStat stat)
|
||||||
|
{
|
||||||
|
return tweakableEngine.GetStatAny<T>(blockID, stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the tweakable stat's value using dynamically-typed variables.
|
||||||
|
/// This is similar to SetStat<T> but without strong type enforcement.
|
||||||
|
/// This should be used in dynamically-typed languages like Python.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The stat's new value.</returns>
|
||||||
|
/// <param name="blockID">The block's id.</param>
|
||||||
|
/// <param name="stat">The stat's enumerated id.</param>
|
||||||
|
/// <param name="value">The stat's new value.</param>
|
||||||
|
public static dynamic SetStatD(uint blockID, TweakableStat stat, dynamic value)
|
||||||
|
{
|
||||||
|
return tweakableEngine.SetStatDynamic(blockID, stat, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the tweakable stat's value.
|
||||||
|
/// If T is not the stat's actual type, an InvalidCastException will be thrown.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The stat's new value.</returns>
|
||||||
|
/// <param name="blockID">The block's id.</param>
|
||||||
|
/// <param name="stat">The stat's enumerated id.</param>
|
||||||
|
/// <param name="value">The stat's new value.</param>
|
||||||
|
/// <typeparam name="T">The stat's type.</typeparam>
|
||||||
|
public static T SetStat<T>(uint blockID, TweakableStat stat, T value)
|
||||||
|
{
|
||||||
|
return tweakableEngine.SetStatAny<T>(blockID, stat, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add another value to the tweakable stat's value using dynamically-typed variables.
|
||||||
|
/// This is similar to AddStat<T> but without strong type enforcement.
|
||||||
|
/// This should be used in dynamically-typed languages like Python.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The stat's new value.</returns>
|
||||||
|
/// <param name="blockID">The block's id.</param>
|
||||||
|
/// <param name="stat">The stat's enumerated id.</param>
|
||||||
|
/// <param name="value">The value to be added to the stat.</param>
|
||||||
|
public static dynamic AddStatD(uint blockID, TweakableStat stat, dynamic value)
|
||||||
|
{
|
||||||
|
return tweakableEngine.AddStatDynamic(blockID, stat, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add another value to the tweakable stat's value.
|
||||||
|
/// If T is not the stat's actual type, an InvalidCastException will be thrown.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The stat's new value.</returns>
|
||||||
|
/// <param name="blockID">The block's id.</param>
|
||||||
|
/// <param name="stat">The stat's enumerated id.</param>
|
||||||
|
/// <param name="value">The value to be added to the stat.</param>
|
||||||
|
/// <typeparam name="T">The stat's type.</typeparam>
|
||||||
|
public static T AddStat<T>(uint blockID, TweakableStat stat, T value)
|
||||||
|
{
|
||||||
|
return tweakableEngine.AddStatAny<T>(blockID, stat, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
GamecraftModdingAPI.Utility.GameEngineManager.AddGameEngine(tweakableEngine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
452
GamecraftModdingAPI/Blocks/TweakableEngine.cs
Normal file
452
GamecraftModdingAPI/Blocks/TweakableEngine.cs
Normal file
|
@ -0,0 +1,452 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using RobocraftX.Blocks;
|
||||||
|
using Gamecraft.Wires;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
public class TweakableEngine : IApiEngine
|
||||||
|
{
|
||||||
|
public string Name { get; } = "GamecraftModdingAPITweakableGameEngine";
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public bool IsInGame = false;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
IsInGame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
IsInGame = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementations for Tweakable static class
|
||||||
|
|
||||||
|
public T GetStatAny<T>(EGID blockID, TweakableStat stat)
|
||||||
|
{
|
||||||
|
switch (stat)
|
||||||
|
{
|
||||||
|
case TweakableStat.TopSpeed:
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
return (T)(object)entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID).maxVelocity;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.Torque:
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
return (T)(object)entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID).maxForce;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MaxExtension:
|
||||||
|
if (entitiesDB.Exists<PistonReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
return (T)(object)entitiesDB.QueryEntity<PistonReadOnlyStruct>(blockID).maxDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MinAngle:
|
||||||
|
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
return (T)(object)entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID).minDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MaxAngle:
|
||||||
|
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
return (T)(object)entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID).maxDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.Reverse:
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
return (T)(object)entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID).reverse;
|
||||||
|
}
|
||||||
|
else if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
return (T)(object)entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID).reverse;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.StartValue:
|
||||||
|
if (entitiesDB.Exists<SignalGeneratorEntityStruct>(blockID))
|
||||||
|
{
|
||||||
|
return (T)(object)entitiesDB.QueryEntity<SignalGeneratorEntityStruct>(blockID).startValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return default(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T GetStatAny<T>(uint blockID, TweakableStat stat)
|
||||||
|
{
|
||||||
|
return GetStatAny<T>(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
public dynamic GetStatDynamic(EGID blockID, TweakableStat stat)
|
||||||
|
{
|
||||||
|
switch (stat)
|
||||||
|
{
|
||||||
|
case TweakableStat.TopSpeed:
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
return entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID).maxVelocity;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.Torque:
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
return entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID).maxForce;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MaxExtension:
|
||||||
|
if (entitiesDB.Exists<PistonReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
return entitiesDB.QueryEntity<PistonReadOnlyStruct>(blockID).maxDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MinAngle:
|
||||||
|
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
return entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID).minDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MaxAngle:
|
||||||
|
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
return entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID).maxDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.Reverse:
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
return entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID).reverse;
|
||||||
|
}
|
||||||
|
else if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
return entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID).reverse;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.StartValue:
|
||||||
|
if (entitiesDB.Exists<SignalGeneratorEntityStruct>(blockID))
|
||||||
|
{
|
||||||
|
return entitiesDB.QueryEntity<SignalGeneratorEntityStruct>(blockID).startValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public dynamic GetStatDynamic(uint blockID, TweakableStat stat)
|
||||||
|
{
|
||||||
|
return GetStatDynamic(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T SetStatAny<T>(EGID blockID, TweakableStat stat, T value)
|
||||||
|
{
|
||||||
|
switch (stat)
|
||||||
|
{
|
||||||
|
case TweakableStat.TopSpeed:
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID);
|
||||||
|
refStruct.maxVelocity = (float)(object)value;
|
||||||
|
return (T)(object)refStruct.maxVelocity;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.Torque:
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID);
|
||||||
|
refStruct.maxForce = (float)(object)value;
|
||||||
|
return (T)(object)refStruct.maxForce;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MaxExtension:
|
||||||
|
if (entitiesDB.Exists<PistonReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref PistonReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<PistonReadOnlyStruct>(blockID);
|
||||||
|
refStruct.maxDeviation = (float)(object)value;
|
||||||
|
return (T)(object)refStruct.maxDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MinAngle:
|
||||||
|
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID);
|
||||||
|
refStruct.minDeviation = (float)(object)value;
|
||||||
|
return (T)(object)refStruct.minDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MaxAngle:
|
||||||
|
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID);
|
||||||
|
refStruct.maxDeviation = (float)(object)value;
|
||||||
|
return (T)(object)refStruct.maxDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.Reverse:
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID);
|
||||||
|
refStruct.reverse = (bool)(object)value;
|
||||||
|
return (T)(object)refStruct.reverse;
|
||||||
|
}
|
||||||
|
else if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID);
|
||||||
|
refStruct.reverse = (bool)(object)value;
|
||||||
|
return (T)(object)refStruct.reverse;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.StartValue:
|
||||||
|
if (entitiesDB.Exists<SignalGeneratorEntityStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref SignalGeneratorEntityStruct refStruct = ref entitiesDB.QueryEntity<SignalGeneratorEntityStruct>(blockID);
|
||||||
|
refStruct.startValue = (float)(object)value;
|
||||||
|
return (T)(object)refStruct.startValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return default(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T SetStatAny<T>(uint blockID, TweakableStat stat, T value)
|
||||||
|
{
|
||||||
|
return SetStatAny<T>(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public dynamic SetStatDynamic(EGID blockID, TweakableStat stat, dynamic value)
|
||||||
|
{
|
||||||
|
switch (stat)
|
||||||
|
{
|
||||||
|
case TweakableStat.TopSpeed:
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID);
|
||||||
|
refStruct.maxVelocity = value;
|
||||||
|
return refStruct.maxVelocity;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.Torque:
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID);
|
||||||
|
refStruct.maxForce = value;
|
||||||
|
return refStruct.maxForce;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MaxExtension:
|
||||||
|
if (entitiesDB.Exists<PistonReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref PistonReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<PistonReadOnlyStruct>(blockID);
|
||||||
|
refStruct.maxDeviation = value;
|
||||||
|
return refStruct.maxDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MinAngle:
|
||||||
|
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID);
|
||||||
|
refStruct.minDeviation = value;
|
||||||
|
return refStruct.minDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MaxAngle:
|
||||||
|
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID);
|
||||||
|
refStruct.maxDeviation = value;
|
||||||
|
return refStruct.maxDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.Reverse:
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID);
|
||||||
|
refStruct.reverse = value;
|
||||||
|
return refStruct.reverse;
|
||||||
|
}
|
||||||
|
else if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID);
|
||||||
|
refStruct.reverse = value;
|
||||||
|
return refStruct.reverse;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.StartValue:
|
||||||
|
if (entitiesDB.Exists<SignalGeneratorEntityStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref SignalGeneratorEntityStruct refStruct = ref entitiesDB.QueryEntity<SignalGeneratorEntityStruct>(blockID);
|
||||||
|
refStruct.startValue = value;
|
||||||
|
return refStruct.startValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public dynamic SetStatDynamic(uint blockID, TweakableStat stat, dynamic value)
|
||||||
|
{
|
||||||
|
return SetStatDynamic(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddStatAny<T>(EGID blockID, TweakableStat stat, T value)
|
||||||
|
{
|
||||||
|
switch (stat)
|
||||||
|
{
|
||||||
|
case TweakableStat.TopSpeed:
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID);
|
||||||
|
refStruct.maxVelocity += (float)(object)value;
|
||||||
|
return (T)(object)refStruct.maxVelocity;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.Torque:
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID);
|
||||||
|
refStruct.maxForce += (float)(object)value;
|
||||||
|
return (T)(object)refStruct.maxForce;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MaxExtension:
|
||||||
|
if (entitiesDB.Exists<PistonReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref PistonReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<PistonReadOnlyStruct>(blockID);
|
||||||
|
refStruct.maxDeviation += (float)(object)value;
|
||||||
|
return (T)(object)refStruct.maxDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MinAngle:
|
||||||
|
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID);
|
||||||
|
refStruct.minDeviation += (float)(object)value;
|
||||||
|
return (T)(object)refStruct.minDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MaxAngle:
|
||||||
|
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID);
|
||||||
|
refStruct.maxDeviation += (float)(object)value;
|
||||||
|
return (T)(object)refStruct.maxDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.Reverse:
|
||||||
|
// '+' is associated with logical OR in some fields, so it technically isn't invalid to "add" booleans
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID);
|
||||||
|
refStruct.reverse = refStruct.reverse || (bool)(object)value;
|
||||||
|
return (T)(object)refStruct.reverse;
|
||||||
|
}
|
||||||
|
else if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID);
|
||||||
|
refStruct.reverse = refStruct.reverse || (bool)(object)value;
|
||||||
|
return (T)(object)refStruct.reverse;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.StartValue:
|
||||||
|
if (entitiesDB.Exists<SignalGeneratorEntityStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref SignalGeneratorEntityStruct refStruct = ref entitiesDB.QueryEntity<SignalGeneratorEntityStruct>(blockID);
|
||||||
|
refStruct.startValue += (float)(object)value;
|
||||||
|
return (T)(object)refStruct.startValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return default(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T AddStatAny<T>(uint blockID, TweakableStat stat, T value)
|
||||||
|
{
|
||||||
|
return AddStatAny<T>(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public dynamic AddStatDynamic(EGID blockID, TweakableStat stat, dynamic value)
|
||||||
|
{
|
||||||
|
switch (stat)
|
||||||
|
{
|
||||||
|
case TweakableStat.TopSpeed:
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID);
|
||||||
|
refStruct.maxVelocity += value;
|
||||||
|
return refStruct.maxVelocity;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.Torque:
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID);
|
||||||
|
refStruct.maxForce += value;
|
||||||
|
return refStruct.maxForce;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MaxExtension:
|
||||||
|
if (entitiesDB.Exists<PistonReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref PistonReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<PistonReadOnlyStruct>(blockID);
|
||||||
|
refStruct.maxDeviation += value;
|
||||||
|
return refStruct.maxDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MinAngle:
|
||||||
|
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID);
|
||||||
|
refStruct.minDeviation += value;
|
||||||
|
return refStruct.minDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.MaxAngle:
|
||||||
|
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID);
|
||||||
|
refStruct.maxDeviation += value;
|
||||||
|
return refStruct.maxDeviation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.Reverse:
|
||||||
|
// '+' is associated with logical OR in some fields, so it technically isn't invalid to "add" booleans
|
||||||
|
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID);
|
||||||
|
refStruct.reverse = refStruct.reverse || value;
|
||||||
|
return refStruct.reverse;
|
||||||
|
}
|
||||||
|
else if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID);
|
||||||
|
refStruct.reverse = refStruct.reverse || value;
|
||||||
|
return refStruct.reverse;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TweakableStat.StartValue:
|
||||||
|
if (entitiesDB.Exists<SignalGeneratorEntityStruct>(blockID))
|
||||||
|
{
|
||||||
|
ref SignalGeneratorEntityStruct refStruct = ref entitiesDB.QueryEntity<SignalGeneratorEntityStruct>(blockID);
|
||||||
|
refStruct.startValue += value;
|
||||||
|
return refStruct.startValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public dynamic AddStatDynamic(uint blockID, TweakableStat stat, dynamic value)
|
||||||
|
{
|
||||||
|
return AddStatDynamic(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
GamecraftModdingAPI/Blocks/TweakableStat.cs
Normal file
14
GamecraftModdingAPI/Blocks/TweakableStat.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
public enum TweakableStat
|
||||||
|
{
|
||||||
|
TopSpeed, // MotorReadOnlyStruct
|
||||||
|
Torque, // MotorReadOnlyStruct
|
||||||
|
MaxExtension, // PistonReadOnlyStruct
|
||||||
|
MinAngle, // ServoReadOnlyStruct
|
||||||
|
MaxAngle, // ServoReadOnlyStruct
|
||||||
|
Reverse, // MotorReadOnlyStruct or ServoReadOnlyStruct
|
||||||
|
StartValue, // SignalGeneratorEntityStruct
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Commands
|
namespace GamecraftModdingAPI.Commands
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// UNIMPLEMENTED!
|
/// UNIMPLEMENTED!
|
|
@ -5,9 +5,10 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Commands
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Commands
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Keeps track of custom commands
|
/// Keeps track of custom commands
|
||||||
|
@ -21,10 +22,6 @@ namespace TechbloxModdingAPI.Commands
|
||||||
|
|
||||||
public static void AddCommand(ICustomCommandEngine engine)
|
public static void AddCommand(ICustomCommandEngine engine)
|
||||||
{
|
{
|
||||||
if (ExistsCommand(engine))
|
|
||||||
{
|
|
||||||
throw new CommandAlreadyExistsException($"Command {engine.Name} already exists");
|
|
||||||
}
|
|
||||||
_customCommands[engine.Name] = engine;
|
_customCommands[engine.Name] = engine;
|
||||||
if (_lastEngineRoot != null)
|
if (_lastEngineRoot != null)
|
||||||
{
|
{
|
42
GamecraftModdingAPI/Commands/CommandPatch.cs
Normal file
42
GamecraftModdingAPI/Commands/CommandPatch.cs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using Harmony;
|
||||||
|
using Svelto.Context;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using RobocraftX;
|
||||||
|
using RobocraftX.Multiplayer;
|
||||||
|
using RobocraftX.StateSync;
|
||||||
|
using Unity.Entities;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Commands
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Patch of RobocraftX.GUI.CommandLine.CommandLineCompositionRoot.Compose<T>()
|
||||||
|
/// </summary>
|
||||||
|
// TODO: fix
|
||||||
|
[HarmonyPatch]
|
||||||
|
//[HarmonyPatch(typeof(RobocraftX.GUI.CommandLine.CommandLineCompositionRoot))]
|
||||||
|
//[HarmonyPatch("Compose")]
|
||||||
|
//[HarmonyPatch("Compose", new Type[] { typeof(UnityContext<FullGameCompositionRoot>), typeof(EnginesRoot), typeof(World), typeof(Action), typeof(MultiplayerInitParameters), typeof(StateSyncRegistrationHelper)})]
|
||||||
|
static class CommandPatch
|
||||||
|
{
|
||||||
|
public static void Postfix(object contextHolder, EnginesRoot enginesRoot, World physicsWorld, Action reloadGame, MultiplayerInitParameters multiplayerParameters, ref StateSyncRegistrationHelper stateSyncReg)
|
||||||
|
{
|
||||||
|
// When a game is loaded, register the command engines
|
||||||
|
CommandManager.RegisterEngines(enginesRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodBase TargetMethod(HarmonyInstance instance)
|
||||||
|
{
|
||||||
|
return typeof(RobocraftX.GUI.CommandLine.CommandLineCompositionRoot).GetMethod("Compose").MakeGenericMethod(typeof(object));
|
||||||
|
//return func.Method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,17 +4,22 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Commands
|
using uREPL;
|
||||||
|
using RobocraftX.CommandLine.Custom;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Commands
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convenient methods for registering commands to Techblox.
|
/// Convenient methods for registering commands to Gamecraft.
|
||||||
/// All methods register to the command line and console block by default.
|
/// All methods register to the command line and console block by default.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class CommandRegistrationHelper
|
public static class CommandRegistrationHelper
|
||||||
{
|
{
|
||||||
public static void Register(string name, Action action, string desc, bool noConsole = false)
|
public static void Register(string name, Action action, string desc, bool noConsole = false)
|
||||||
{
|
{
|
||||||
CustomCommands.Register(name, action, desc);
|
RuntimeCommands.Register(name, action, desc);
|
||||||
|
if (noConsole) { return; }
|
||||||
|
ConsoleCommands.Register(name, action, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Register(string name, Action<object> action, string desc, bool noConsole = false)
|
public static void Register(string name, Action<object> action, string desc, bool noConsole = false)
|
||||||
|
@ -34,42 +39,50 @@ namespace TechbloxModdingAPI.Commands
|
||||||
|
|
||||||
public static void Register<Param0>(string name, Action<Param0> action, string desc, bool noConsole = false)
|
public static void Register<Param0>(string name, Action<Param0> action, string desc, bool noConsole = false)
|
||||||
{
|
{
|
||||||
CustomCommands.Register(name, action, desc);
|
RuntimeCommands.Register<Param0>(name, action, desc);
|
||||||
|
if (noConsole) { return; }
|
||||||
|
ConsoleCommands.Register<Param0>(name, action, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Register<Param0, Param1>(string name, Action<Param0, Param1> action, string desc, bool noConsole = false)
|
public static void Register<Param0, Param1>(string name, Action<Param0, Param1> action, string desc, bool noConsole = false)
|
||||||
{
|
{
|
||||||
CustomCommands.Register(name, action, desc);
|
RuntimeCommands.Register<Param0, Param1>(name, action, desc);
|
||||||
|
if (noConsole) { return; }
|
||||||
|
ConsoleCommands.Register<Param0, Param1>(name, action, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Register<Param0, Param1, Param2>(string name, Action<Param0, Param1, Param2> action, string desc, bool noConsole = false)
|
public static void Register<Param0, Param1, Param2>(string name, Action<Param0, Param1, Param2> action, string desc, bool noConsole = false)
|
||||||
{
|
{
|
||||||
CustomCommands.Register(name, action, desc);
|
RuntimeCommands.Register<Param0, Param1, Param2>(name, action, desc);
|
||||||
|
if (noConsole) { return; }
|
||||||
|
ConsoleCommands.Register<Param0, Param1, Param2>(name, action, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Unregister(string name, bool noConsole = false)
|
public static void Unregister(string name, bool noConsole = false)
|
||||||
{
|
{
|
||||||
CustomCommands.Unregister(name);
|
RuntimeCommands.Unregister(name);
|
||||||
|
if (noConsole) { return; }
|
||||||
|
ConsoleCommands.Unregister(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Call(string name)
|
public static void Call(string name)
|
||||||
{
|
{
|
||||||
CustomCommands.Call(name);
|
RuntimeCommands.Call(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Call<Param0>(string name, Param0 param0)
|
public static void Call<Param0>(string name, Param0 param0)
|
||||||
{
|
{
|
||||||
CustomCommands.Call(name, param0);
|
RuntimeCommands.Call<Param0>(name, param0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Call<Param0, Param1>(string name, Param0 param0, Param1 param1)
|
public static void Call<Param0, Param1>(string name, Param0 param0, Param1 param1)
|
||||||
{
|
{
|
||||||
CustomCommands.Call(name, param0, param1);
|
RuntimeCommands.Call<Param0, Param1>(name, param0, param1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Call<Param0, Param1, Param2>(string name, Param0 param0, Param1 param1, Param2 param2)
|
public static void Call<Param0, Param1, Param2>(string name, Param0 param0, Param1 param1, Param2 param2)
|
||||||
{
|
{
|
||||||
CustomCommands.Call(name, param0, param1, param2);
|
RuntimeCommands.Call<Param0, Param1, Param2>(name, param0, param1, param2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
42
GamecraftModdingAPI/Commands/ExistingCommands.cs
Normal file
42
GamecraftModdingAPI/Commands/ExistingCommands.cs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using uREPL;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Commands
|
||||||
|
{
|
||||||
|
public static class ExistingCommands
|
||||||
|
{
|
||||||
|
public static void Call(string commandName)
|
||||||
|
{
|
||||||
|
RuntimeCommands.Call(commandName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Call<Arg0>(string commandName, Arg0 arg0)
|
||||||
|
{
|
||||||
|
RuntimeCommands.Call<Arg0>(commandName, arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Call<Arg0, Arg1>(string commandName, Arg0 arg0, Arg1 arg1)
|
||||||
|
{
|
||||||
|
RuntimeCommands.Call<Arg0, Arg1>(commandName, arg0, arg1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Call<Arg0, Arg1, Arg2>(string commandName, Arg0 arg0, Arg1 arg1, Arg2 arg2)
|
||||||
|
{
|
||||||
|
RuntimeCommands.Call<Arg0, Arg1, Arg2>(commandName, arg0, arg1, arg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool Exists(string commandName)
|
||||||
|
{
|
||||||
|
return RuntimeCommands.HasRegistered(commandName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string[] GetCommandNames()
|
||||||
|
{
|
||||||
|
var keys = RuntimeCommands.table.Keys;
|
||||||
|
string[] res = new string[keys.Count];
|
||||||
|
keys.CopyTo(res, 0);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,15 +6,12 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
|
|
||||||
using TechbloxModdingAPI.Utility;
|
using GamecraftModdingAPI.Utility;
|
||||||
using TechbloxModdingAPI.Engines;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Commands
|
namespace GamecraftModdingAPI.Commands
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Engine interface to handle command operations.
|
/// Engine interface to handle command operations
|
||||||
/// If you are using implementing this yourself, you must manually register the command.
|
|
||||||
/// See SimpleCustomCommandEngine's Ready() and Dispose() methods for an example of command registration.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ICustomCommandEngine : IApiEngine
|
public interface ICustomCommandEngine : IApiEngine
|
||||||
{
|
{
|
|
@ -5,9 +5,8 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Commands
|
namespace GamecraftModdingAPI.Commands
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A simple implementation of ICustomCommandEngine sufficient for most commands.
|
/// A simple implementation of ICustomCommandEngine sufficient for most commands.
|
||||||
|
@ -32,18 +31,16 @@ namespace TechbloxModdingAPI.Commands
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { set; private get; }
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
public bool isRemovable => true;
|
public void Dispose()
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
{
|
||||||
Logging.MetaDebugLog($"Unregistering SimpleCustomCommandEngine {this.Name}");
|
GamecraftModdingAPI.Utility.Logging.MetaDebugLog($"Unregistering SimpleCustomCommandEngine {this.Name}");
|
||||||
CommandRegistrationHelper.Unregister(this.Name);
|
CommandRegistrationHelper.Unregister(this.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Ready()
|
public void Ready()
|
||||||
{
|
{
|
||||||
Logging.MetaDebugLog($"Registering SimpleCustomCommandEngine {this.Name}");
|
GamecraftModdingAPI.Utility.Logging.MetaDebugLog($"Registering SimpleCustomCommandEngine {this.Name}");
|
||||||
CommandRegistrationHelper.Register(this.Name, this.InvokeCatchError, this.Description);
|
CommandRegistrationHelper.Register(this.Name, this.runCommand, this.Description);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -58,24 +55,5 @@ namespace TechbloxModdingAPI.Commands
|
||||||
this.Name = name;
|
this.Name = name;
|
||||||
this.Description = description;
|
this.Description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Invoke()
|
|
||||||
{
|
|
||||||
runCommand();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InvokeCatchError()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
runCommand();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
CommandRuntimeException wrappedException = new CommandRuntimeException($"Command {Name} threw an exception when executed", e);
|
|
||||||
Logging.LogWarning(wrappedException.ToString());
|
|
||||||
Logging.CommandLogError(wrappedException.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,9 +5,8 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Commands
|
namespace GamecraftModdingAPI.Commands
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A simple implementation of ICustomCommandEngine sufficient for most commands.
|
/// A simple implementation of ICustomCommandEngine sufficient for most commands.
|
||||||
|
@ -23,18 +22,16 @@ namespace TechbloxModdingAPI.Commands
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { set; private get; }
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
public bool isRemovable => true;
|
public void Dispose()
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
{
|
||||||
Logging.MetaDebugLog($"Unregistering SimpleCustomCommandEngine {this.Name}");
|
GamecraftModdingAPI.Utility.Logging.MetaDebugLog($"Unregistering SimpleCustomCommandEngine {this.Name}");
|
||||||
CommandRegistrationHelper.Unregister(this.Name);
|
CommandRegistrationHelper.Unregister(this.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Ready()
|
public void Ready()
|
||||||
{
|
{
|
||||||
Logging.MetaDebugLog($"Registering SimpleCustomCommandEngine {this.Name}");
|
GamecraftModdingAPI.Utility.Logging.MetaDebugLog($"Registering SimpleCustomCommandEngine {this.Name}");
|
||||||
CommandRegistrationHelper.Register<A>(this.Name, this.InvokeCatchError, this.Description);
|
CommandRegistrationHelper.Register<A>(this.Name, this.runCommand, this.Description);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -48,25 +45,6 @@ namespace TechbloxModdingAPI.Commands
|
||||||
this.runCommand = command;
|
this.runCommand = command;
|
||||||
this.Name = name;
|
this.Name = name;
|
||||||
this.Description = description;
|
this.Description = description;
|
||||||
}
|
|
||||||
|
|
||||||
public void Invoke(A a)
|
|
||||||
{
|
|
||||||
runCommand(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InvokeCatchError(A a)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
runCommand(a);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
CommandRuntimeException wrappedException = new CommandRuntimeException($"Command {Name} threw an exception when executed", e);
|
|
||||||
Logging.LogWarning(wrappedException.ToString());
|
|
||||||
Logging.CommandLogError(wrappedException.ToString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,9 +5,8 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Commands
|
namespace GamecraftModdingAPI.Commands
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A simple implementation of ICustomCommandEngine sufficient for most commands.
|
/// A simple implementation of ICustomCommandEngine sufficient for most commands.
|
||||||
|
@ -23,18 +22,16 @@ namespace TechbloxModdingAPI.Commands
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { set; private get; }
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
public bool isRemovable => true;
|
public void Dispose()
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
{
|
||||||
Logging.MetaDebugLog($"Unregistering SimpleCustomCommandEngine {this.Name}");
|
GamecraftModdingAPI.Utility.Logging.MetaDebugLog($"Unregistering SimpleCustomCommandEngine {this.Name}");
|
||||||
CommandRegistrationHelper.Unregister(this.Name);
|
CommandRegistrationHelper.Unregister(this.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Ready()
|
public void Ready()
|
||||||
{
|
{
|
||||||
Logging.MetaDebugLog($"Registering SimpleCustomCommandEngine {this.Name}");
|
GamecraftModdingAPI.Utility.Logging.MetaDebugLog($"Registering SimpleCustomCommandEngine {this.Name}");
|
||||||
CommandRegistrationHelper.Register<A,B>(this.Name, this.InvokeCatchError, this.Description);
|
CommandRegistrationHelper.Register<A,B>(this.Name, this.runCommand, this.Description);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -48,25 +45,6 @@ namespace TechbloxModdingAPI.Commands
|
||||||
this.runCommand = command;
|
this.runCommand = command;
|
||||||
this.Name = name;
|
this.Name = name;
|
||||||
this.Description = description;
|
this.Description = description;
|
||||||
}
|
|
||||||
|
|
||||||
public void Invoke(A a, B b)
|
|
||||||
{
|
|
||||||
runCommand(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InvokeCatchError(A a, B b)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
runCommand(a, b);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
CommandRuntimeException wrappedException = new CommandRuntimeException($"Command {Name} threw an exception when executed", e);
|
|
||||||
Logging.LogWarning(wrappedException.ToString());
|
|
||||||
Logging.CommandLogError(wrappedException.ToString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,9 +5,8 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Commands
|
namespace GamecraftModdingAPI.Commands
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A simple implementation of ICustomCommandEngine sufficient for most commands.
|
/// A simple implementation of ICustomCommandEngine sufficient for most commands.
|
||||||
|
@ -23,18 +22,16 @@ namespace TechbloxModdingAPI.Commands
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { set; private get; }
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
public bool isRemovable => true;
|
public void Dispose()
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
{
|
||||||
Logging.MetaDebugLog($"Unregistering SimpleCustomCommandEngine {this.Name}");
|
GamecraftModdingAPI.Utility.Logging.MetaDebugLog($"Unregistering SimpleCustomCommandEngine {this.Name}");
|
||||||
CommandRegistrationHelper.Unregister(this.Name);
|
CommandRegistrationHelper.Unregister(this.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Ready()
|
public void Ready()
|
||||||
{
|
{
|
||||||
Logging.MetaDebugLog($"Registering SimpleCustomCommandEngine {this.Name}");
|
GamecraftModdingAPI.Utility.Logging.MetaDebugLog($"Registering SimpleCustomCommandEngine {this.Name}");
|
||||||
CommandRegistrationHelper.Register<A,B,C>(this.Name, this.InvokeCatchError, this.Description);
|
CommandRegistrationHelper.Register<A,B,C>(this.Name, this.runCommand, this.Description);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -48,25 +45,6 @@ namespace TechbloxModdingAPI.Commands
|
||||||
this.runCommand = command;
|
this.runCommand = command;
|
||||||
this.Name = name;
|
this.Name = name;
|
||||||
this.Description = description;
|
this.Description = description;
|
||||||
}
|
|
||||||
|
|
||||||
public void Invoke(A a, B b, C c)
|
|
||||||
{
|
|
||||||
runCommand(a, b, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InvokeCatchError(A a, B b, C c)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
runCommand(a, b, c);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
CommandRuntimeException wrappedException = new CommandRuntimeException($"Command {Name} threw an exception when executed", e);
|
|
||||||
Logging.LogWarning(wrappedException.ToString());
|
|
||||||
Logging.CommandLogError(wrappedException.ToString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Harmony;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.StateSync;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Patch of RobocraftX.StateSync.DeterministicStepCompositionRoot.ComposeEnginesGroups(...)
|
||||||
|
/// </summary>
|
||||||
|
//[HarmonyPatch(typeof(DeterministicStepCompositionRoot), "DeterministicCompose")]
|
||||||
|
[HarmonyPatch]
|
||||||
|
class GameHostTransitionDeterministicGroupEnginePatch
|
||||||
|
{
|
||||||
|
|
||||||
|
public static readonly GameStateBuildEmitterEngine buildEngine = new GameStateBuildEmitterEngine();
|
||||||
|
|
||||||
|
public static readonly GameStateSimulationEmitterEngine simEngine = new GameStateSimulationEmitterEngine();
|
||||||
|
|
||||||
|
public static void Postfix()
|
||||||
|
{
|
||||||
|
//stateSyncReg.buildModeInitializationEngines.Add(buildEngine);
|
||||||
|
//stateSyncReg.simulationModeInitializationEngines.Add(simEngine);
|
||||||
|
//enginesRoot.AddEngine(buildEngine);
|
||||||
|
//enginesRoot.AddEngine(simEngine);
|
||||||
|
buildEngine.EmitIfBuildMode();
|
||||||
|
simEngine.EmitIfSimMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyTargetMethod]
|
||||||
|
public static MethodBase TargetMethod(HarmonyInstance harmonyInstance)
|
||||||
|
{
|
||||||
|
return AccessTools.Method(AccessTools.TypeByName("RobocraftX.StateSync.GameHostTransitionDeterministicGroupEngine"), "EndTransition");
|
||||||
|
//.MakeGenericMethod(typeof(CosmeticEnginesSequenceBuildOrder), typeof(CosmeticEnginesSequenceSimOrder), typeof(DeterministicToCosmeticSyncBuildOrder), typeof(DeterministicToCosmeticSyncSimOrder));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
GamecraftModdingAPI/Events/EventEngineFactory.cs
Normal file
60
GamecraftModdingAPI/Events/EventEngineFactory.cs
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Convenient factories for mod event engines
|
||||||
|
/// </summary>
|
||||||
|
public static class EventEngineFactory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Factory method which automatically adds the SimpleEventHandlerEngine to the Manager
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the engine</param>
|
||||||
|
/// <param name="type">The type of event to handle</param>
|
||||||
|
/// <param name="onActivated">The operation to do when the event is created</param>
|
||||||
|
/// <param name="onDestroyed">The operation to do when the event is destroyed (if applicable)</param>
|
||||||
|
/// <returns>The created object</returns>
|
||||||
|
public static SimpleEventHandlerEngine CreateAddSimpleHandler(string name, int type, Action onActivated, Action onDestroyed)
|
||||||
|
{
|
||||||
|
var engine = new SimpleEventHandlerEngine(onActivated, onDestroyed, type, name);
|
||||||
|
EventManager.AddEventHandler(engine);
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Factory method which automatically adds the SimpleEventHandlerEngine to the Manager
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the engine</param>
|
||||||
|
/// <param name="type">The type of event to handle</param>
|
||||||
|
/// <param name="onActivated">The operation to do when the event is created</param>
|
||||||
|
/// <param name="onDestroyed">The operation to do when the event is destroyed (if applicable)</param>
|
||||||
|
/// <returns>The created object</returns>
|
||||||
|
public static SimpleEventHandlerEngine CreateAddSimpleHandler(string name, int type, Action<EntitiesDB> onActivated, Action<EntitiesDB> onDestroyed)
|
||||||
|
{
|
||||||
|
var engine = new SimpleEventHandlerEngine(onActivated, onDestroyed, type, name);
|
||||||
|
EventManager.AddEventHandler(engine);
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Factory method which automatically adds the SimpleEventEmitterEngine to the Manager
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the engine</param>
|
||||||
|
/// <param name="type">The type of event to emit</param>
|
||||||
|
/// <param name="isRemovable">Will removing this engine not break your code?</param>
|
||||||
|
/// <returns>The created object</returns>
|
||||||
|
public static SimpleEventEmitterEngine CreateAddSimpleEmitter(string name, int type, bool isRemovable = true)
|
||||||
|
{
|
||||||
|
var engine = new SimpleEventEmitterEngine(type, name, isRemovable);
|
||||||
|
EventManager.AddEventEmitter(engine);
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
120
GamecraftModdingAPI/Events/EventManager.cs
Normal file
120
GamecraftModdingAPI/Events/EventManager.cs
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Keeps track of event handlers and emitters.
|
||||||
|
/// This is used to add, remove and get API event handlers and emitters.
|
||||||
|
/// </summary>
|
||||||
|
public static class EventManager
|
||||||
|
{
|
||||||
|
private static Dictionary<string, IEventEmitterEngine> _eventEmitters = new Dictionary<string, IEventEmitterEngine>();
|
||||||
|
|
||||||
|
private static Dictionary<string, IEventHandlerEngine> _eventHandlers = new Dictionary<string, IEventHandlerEngine>();
|
||||||
|
|
||||||
|
private static EnginesRoot _lastEngineRoot;
|
||||||
|
|
||||||
|
// event handler management
|
||||||
|
|
||||||
|
public static void AddEventHandler(IEventHandlerEngine engine)
|
||||||
|
{
|
||||||
|
_eventHandlers[engine.Name] = engine;
|
||||||
|
if (_lastEngineRoot != null)
|
||||||
|
{
|
||||||
|
Logging.MetaDebugLog($"Registering IEventHandlerEngine {engine.Name}");
|
||||||
|
_lastEngineRoot.AddEngine(engine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ExistsEventHandler(string name)
|
||||||
|
{
|
||||||
|
return _eventHandlers.ContainsKey(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ExistsEventHandler(IEventHandlerEngine engine)
|
||||||
|
{
|
||||||
|
return ExistsEventHandler(engine.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEventHandlerEngine GetEventHandler(string name)
|
||||||
|
{
|
||||||
|
return _eventHandlers[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string[] GetEventHandlerNames()
|
||||||
|
{
|
||||||
|
return _eventHandlers.Keys.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RemoveEventHandler(string name)
|
||||||
|
{
|
||||||
|
_eventHandlers.Remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// event emitter management
|
||||||
|
|
||||||
|
public static void AddEventEmitter(IEventEmitterEngine engine)
|
||||||
|
{
|
||||||
|
_eventEmitters[engine.Name] = engine;
|
||||||
|
if (_lastEngineRoot != null)
|
||||||
|
{
|
||||||
|
Logging.MetaDebugLog($"Registering IEventEmitterEngine {engine.Name}");
|
||||||
|
_lastEngineRoot.AddEngine(engine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ExistsEventEmitter(string name)
|
||||||
|
{
|
||||||
|
return _eventEmitters.ContainsKey(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ExistsEventEmitter(IEventEmitterEngine engine)
|
||||||
|
{
|
||||||
|
return ExistsEventEmitter(engine.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEventEmitterEngine GetEventEmitter(string name)
|
||||||
|
{
|
||||||
|
return _eventEmitters[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string[] GetEventEmitterNames()
|
||||||
|
{
|
||||||
|
return _eventEmitters.Keys.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RemoveEventEmitter(string name)
|
||||||
|
{
|
||||||
|
if (_eventEmitters[name].isRemovable)
|
||||||
|
{
|
||||||
|
_eventEmitters.Remove(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterEngines(EnginesRoot enginesRoot)
|
||||||
|
{
|
||||||
|
_lastEngineRoot = enginesRoot;
|
||||||
|
// Register handlers before emitters so no events are missed
|
||||||
|
var entityFactory = enginesRoot.GenerateEntityFactory();
|
||||||
|
foreach (var key in _eventHandlers.Keys)
|
||||||
|
{
|
||||||
|
Logging.MetaDebugLog($"Registering IEventHandlerEngine {_eventHandlers[key].Name}");
|
||||||
|
enginesRoot.AddEngine(_eventHandlers[key]);
|
||||||
|
}
|
||||||
|
foreach (var key in _eventEmitters.Keys)
|
||||||
|
{
|
||||||
|
Logging.MetaDebugLog($"Registering IEventEmitterEngine {_eventEmitters[key].Name}");
|
||||||
|
_eventEmitters[key].Factory = entityFactory;
|
||||||
|
enginesRoot.AddEngine(_eventEmitters[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
GamecraftModdingAPI/Events/EventType.cs
Normal file
24
GamecraftModdingAPI/Events/EventType.cs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Built-in event types.
|
||||||
|
/// These are configured to fire when the API is initialized.
|
||||||
|
/// </summary>
|
||||||
|
public enum EventType
|
||||||
|
{
|
||||||
|
ApplicationInitialized,
|
||||||
|
Menu,
|
||||||
|
MenuSwitchedTo,
|
||||||
|
Game,
|
||||||
|
GameReloaded,
|
||||||
|
GameSwitchedTo,
|
||||||
|
SimulationSwitchedTo,
|
||||||
|
BuildSwitchedTo
|
||||||
|
}
|
||||||
|
}
|
56
GamecraftModdingAPI/Events/GameActivatedComposePatch.cs
Normal file
56
GamecraftModdingAPI/Events/GameActivatedComposePatch.cs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Harmony;
|
||||||
|
using RobocraftX;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
using RobocraftX.CR.MainGame;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Patch of RobocraftX.FullGameCompositionRoot.ActivateGame()
|
||||||
|
/// </summary>
|
||||||
|
[HarmonyPatch]
|
||||||
|
class GameActivatedComposePatch
|
||||||
|
{
|
||||||
|
public static bool IsGameSwitching = false;
|
||||||
|
|
||||||
|
public static bool IsGameReloading = false;
|
||||||
|
|
||||||
|
public static void Postfix(ref object contextHolder, ref EnginesRoot enginesRoot)
|
||||||
|
{
|
||||||
|
// register custom game engines
|
||||||
|
GameEngineManager.RegisterEngines(enginesRoot);
|
||||||
|
// A new EnginesRoot is always created when ActivateGame is called
|
||||||
|
// so all event emitters and handlers must be re-registered.
|
||||||
|
EventManager.RegisterEngines(enginesRoot);
|
||||||
|
Logging.Log("Dispatching Game Activated event");
|
||||||
|
EventManager.GetEventEmitter("GamecraftModdingAPIGameActivatedEventEmitter").Emit();
|
||||||
|
if (IsGameSwitching)
|
||||||
|
{
|
||||||
|
IsGameSwitching = false;
|
||||||
|
Logging.Log("Dispatching Game Switched To event");
|
||||||
|
EventManager.GetEventEmitter("GamecraftModdingAPIGameSwitchedToEventEmitter").Emit();
|
||||||
|
}
|
||||||
|
if (IsGameReloading)
|
||||||
|
{
|
||||||
|
IsGameReloading = false;
|
||||||
|
Logging.Log("Dispatching Game Reloaded event");
|
||||||
|
EventManager.GetEventEmitter("GamecraftModdingAPIGameReloadedEventEmitter").Emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodBase TargetMethod()
|
||||||
|
{
|
||||||
|
return typeof(MainGameCompositionRoot).GetMethods().First(m => m.Name == "Compose")
|
||||||
|
.MakeGenericMethod(typeof(object));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
GamecraftModdingAPI/Events/GameReloadedPatch.cs
Normal file
25
GamecraftModdingAPI/Events/GameReloadedPatch.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Harmony;
|
||||||
|
using RobocraftX;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Patch of RobocraftX.FullGameCompositionRoot.ReloadGame()
|
||||||
|
/// </summary>
|
||||||
|
[HarmonyPatch(typeof(FullGameCompositionRoot), "ReloadGame")]
|
||||||
|
class GameReloadedPatch
|
||||||
|
{
|
||||||
|
public static void Postfix()
|
||||||
|
{
|
||||||
|
GameActivatedComposePatch.IsGameReloading = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
GamecraftModdingAPI/Events/GameStateBuildEmitterEngine.cs
Normal file
54
GamecraftModdingAPI/Events/GameStateBuildEmitterEngine.cs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using Unity.Jobs;
|
||||||
|
using RobocraftX.SimulationModeState;
|
||||||
|
using RobocraftX.StateSync;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Event emitter engine for switching to to build mode.
|
||||||
|
/// </summary>
|
||||||
|
public class GameStateBuildEmitterEngine : IEventEmitterEngine, IInitializeOnBuildStart
|
||||||
|
{
|
||||||
|
public string Name { get; } = "GamecraftModdingAPIGameStateBuildEventEmitter" ;
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public int type { get; } = (int)EventType.BuildSwitchedTo;
|
||||||
|
|
||||||
|
public bool isRemovable { get; } = false;
|
||||||
|
|
||||||
|
public IEntityFactory Factory { set; private get; }
|
||||||
|
|
||||||
|
public void Dispose() { }
|
||||||
|
|
||||||
|
public void Emit()
|
||||||
|
{
|
||||||
|
Logging.Log("Dispatching Build Switched To event");
|
||||||
|
if (Factory == null) { return; }
|
||||||
|
Factory.BuildEntity<ModEventEntityDescriptor>(ApiExclusiveGroups.eventID++, ApiExclusiveGroups.eventsExclusiveGroup)
|
||||||
|
.Init(new ModEventEntityStruct { type = type });
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EmitIfBuildMode()
|
||||||
|
{
|
||||||
|
//Logging.MetaDebugLog($"nextSimulationMode: {entitiesDB.QueryUniqueEntity<SimulationModeStateEntityStruct>(SimulationModeStateExclusiveGroups.GAME_STATE_GROUP).nextSimulationMode}");
|
||||||
|
if (entitiesDB.QueryUniqueEntity<SimulationModeStateEntityStruct>(SimulationModeStateExclusiveGroups.GAME_STATE_GROUP).nextSimulationMode == SimulationMode.Build)
|
||||||
|
{
|
||||||
|
Emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JobHandle OnInitializeBuildMode()
|
||||||
|
{
|
||||||
|
Emit();
|
||||||
|
return default(JobHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready() { }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using Unity.Jobs;
|
||||||
|
using RobocraftX.SimulationModeState;
|
||||||
|
using RobocraftX.StateSync;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Event emitter engine for switching to simulation mode.
|
||||||
|
/// </summary>
|
||||||
|
public class GameStateSimulationEmitterEngine : IEventEmitterEngine, IInitializeOnSimulationStart
|
||||||
|
{
|
||||||
|
public string Name { get; } = "GamecraftModdingAPIGameStateSimulationEventEmitter" ;
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public int type { get; } = (int)EventType.SimulationSwitchedTo;
|
||||||
|
|
||||||
|
public bool isRemovable { get; } = false;
|
||||||
|
|
||||||
|
public IEntityFactory Factory { set; private get; }
|
||||||
|
|
||||||
|
public void Dispose() { }
|
||||||
|
|
||||||
|
public void Emit()
|
||||||
|
{
|
||||||
|
Logging.Log("Dispatching Simulation Switched To event");
|
||||||
|
if (Factory == null) { return; }
|
||||||
|
Factory.BuildEntity<ModEventEntityDescriptor>(ApiExclusiveGroups.eventID++, ApiExclusiveGroups.eventsExclusiveGroup)
|
||||||
|
.Init(new ModEventEntityStruct { type = type });
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EmitIfSimMode()
|
||||||
|
{
|
||||||
|
if (entitiesDB.QueryUniqueEntity<SimulationModeStateEntityStruct>(SimulationModeStateExclusiveGroups.GAME_STATE_GROUP).nextSimulationMode == SimulationMode.Simulation)
|
||||||
|
{
|
||||||
|
Emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JobHandle OnInitializeSimulationMode()
|
||||||
|
{
|
||||||
|
Emit();
|
||||||
|
return default(JobHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready() { }
|
||||||
|
}
|
||||||
|
}
|
29
GamecraftModdingAPI/Events/GameSwitchedToPatch.cs
Normal file
29
GamecraftModdingAPI/Events/GameSwitchedToPatch.cs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using Harmony;
|
||||||
|
using RobocraftX;
|
||||||
|
using RobocraftX.CR.MainGame;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Patch of RobocraftX.FullGameCompositionRoot.ActivateGame()
|
||||||
|
/// (scheduled for execution during RobocraftX.FullGameCompositionRoot.SwitchToGame())
|
||||||
|
/// </summary>
|
||||||
|
[HarmonyPatch(typeof(FullGameCompositionRoot), "SwitchToGame")]
|
||||||
|
class GameSwitchedToPatch
|
||||||
|
{
|
||||||
|
public static void Prefix()
|
||||||
|
{
|
||||||
|
GameActivatedComposePatch.IsGameSwitching = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
GamecraftModdingAPI/Events/IEventEmitterEngine.cs
Normal file
40
GamecraftModdingAPI/Events/IEventEmitterEngine.cs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Engine interface to create a ModEventEntityStruct in entitiesDB when Emit() is called.
|
||||||
|
/// </summary>
|
||||||
|
public interface IEventEmitterEngine : IApiEngine
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of event emitted
|
||||||
|
/// </summary>
|
||||||
|
int type { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the emitter can be removed with Manager.RemoveEventEmitter(name)
|
||||||
|
/// </summary>
|
||||||
|
bool isRemovable { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The EntityFactory for the entitiesDB.
|
||||||
|
/// Use this to create a ModEventEntityStruct when Emit() is called.
|
||||||
|
/// </summary>
|
||||||
|
IEntityFactory Factory { set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Emit the event so IEventHandlerEngines can handle it.
|
||||||
|
/// Call Emit() to trigger the IEventEmitterEngine's event.
|
||||||
|
/// </summary>
|
||||||
|
void Emit();
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,14 +7,14 @@ using System.Threading.Tasks;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.Internal;
|
using Svelto.ECS.Internal;
|
||||||
|
|
||||||
using TechbloxModdingAPI.Events;
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Engines
|
namespace GamecraftModdingAPI.Events
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Engine interface to handle ModEventEntityStruct events emitted by IEventEmitterEngines.
|
/// Engine interface to handle ModEventEntityStruct events emitted by IEventEmitterEngines.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IReactionaryEngine<T> : IApiEngine, IReactOnAddAndRemove<T> where T : unmanaged, IEntityComponent
|
public interface IEventHandlerEngine : IApiEngine, IReactOnAddAndRemove<ModEventEntityStruct>, IReactOnAddAndRemove
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
41
GamecraftModdingAPI/Events/MenuActivatedPatch.cs
Normal file
41
GamecraftModdingAPI/Events/MenuActivatedPatch.cs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Harmony;
|
||||||
|
using RobocraftX;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Patch of RobocraftX.FullGameCompositionRoot.ActivateMenu()
|
||||||
|
/// </summary>
|
||||||
|
[HarmonyPatch(typeof(FullGameCompositionRoot), "ActivateMenu")]
|
||||||
|
class MenuActivatedPatch
|
||||||
|
{
|
||||||
|
|
||||||
|
private static bool firstLoad = true;
|
||||||
|
public static void Postfix(ref EnginesRoot ____frontEndEnginesRoot, FullGameCompositionRoot __instance)
|
||||||
|
{
|
||||||
|
// register custom menu engines
|
||||||
|
MenuEngineManager.RegisterEngines(____frontEndEnginesRoot);
|
||||||
|
// A new EnginesRoot is always created when ActivateMenu is called
|
||||||
|
// so all event emitters and handlers must be re-registered.
|
||||||
|
EventManager.RegisterEngines(____frontEndEnginesRoot);
|
||||||
|
if (firstLoad)
|
||||||
|
{
|
||||||
|
firstLoad = false;
|
||||||
|
FullGameFields.Init(__instance);
|
||||||
|
Logging.Log("Dispatching App Init event");
|
||||||
|
EventManager.GetEventEmitter("GamecraftModdingAPIApplicationInitializedEventEmitter").Emit();
|
||||||
|
}
|
||||||
|
Logging.Log("Dispatching Menu Activated event");
|
||||||
|
EventManager.GetEventEmitter("GamecraftModdingAPIMenuActivatedEventEmitter").Emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
GamecraftModdingAPI/Events/MenuSwitchedToPatch.cs
Normal file
28
GamecraftModdingAPI/Events/MenuSwitchedToPatch.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Harmony;
|
||||||
|
using RobocraftX;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Patch of RobocraftX.FullGameCompositionRoot.SwitchToMenu()
|
||||||
|
/// </summary>
|
||||||
|
[HarmonyPatch(typeof(FullGameCompositionRoot), "SwitchToMenu")]
|
||||||
|
class MenuSwitchedToPatch
|
||||||
|
{
|
||||||
|
public static void Postfix()
|
||||||
|
{
|
||||||
|
// Event emitters and handlers should already be registered by MenuActivated event
|
||||||
|
Logging.Log("Dispatching Menu Switched To event");
|
||||||
|
EventManager.GetEventEmitter("GamecraftModdingAPIMenuSwitchedToEventEmitter").Emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
GamecraftModdingAPI/Events/ModEventEntityDescriptor.cs
Normal file
17
GamecraftModdingAPI/Events/ModEventEntityDescriptor.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// EntityDescriptor for creating ModEventEntityStructs
|
||||||
|
/// </summary>
|
||||||
|
public class ModEventEntityDescriptor : GenericEntityDescriptor<ModEventEntityStruct>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
23
GamecraftModdingAPI/Events/ModEventEntityStruct.cs
Normal file
23
GamecraftModdingAPI/Events/ModEventEntityStruct.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The event entity struct
|
||||||
|
/// </summary>
|
||||||
|
public struct ModEventEntityStruct : IEntityComponent, INeedEGID
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of event that has been emitted
|
||||||
|
/// </summary>
|
||||||
|
public int type;
|
||||||
|
|
||||||
|
public EGID ID { get; set; }
|
||||||
|
}
|
||||||
|
}
|
65
GamecraftModdingAPI/Events/SimpleEventEmitterEngine.cs
Normal file
65
GamecraftModdingAPI/Events/SimpleEventEmitterEngine.cs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Svelto.ECS;
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A simple implementation of IEventEmitterEngine sufficient for most uses
|
||||||
|
/// </summary>
|
||||||
|
public class SimpleEventEmitterEngine : IEventEmitterEngine
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public int type { get; set; }
|
||||||
|
|
||||||
|
public bool isRemovable { get; }
|
||||||
|
|
||||||
|
public IEntityFactory Factory { private get; set; }
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public void Ready() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Emit the event
|
||||||
|
/// </summary>
|
||||||
|
public void Emit()
|
||||||
|
{
|
||||||
|
Factory.BuildEntity<ModEventEntityDescriptor>(ApiExclusiveGroups.eventID++, ApiExclusiveGroups.eventsExclusiveGroup)
|
||||||
|
.Init(new ModEventEntityStruct { type = type });
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Construct the engine
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The EventType to use for ModEventEntityStruct.type</param>
|
||||||
|
/// <param name="name">The name of this engine</param>
|
||||||
|
/// <param name="isRemovable">Will removing this engine not break your code?</param>
|
||||||
|
public SimpleEventEmitterEngine(EventType type, string name, bool isRemovable = true)
|
||||||
|
{
|
||||||
|
this.type = (int)type;
|
||||||
|
this.Name = name;
|
||||||
|
this.isRemovable = isRemovable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Construct the engine
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The object to use for ModEventEntityStruct.type</param>
|
||||||
|
/// <param name="name">The name of this engine</param>
|
||||||
|
/// <param name="isRemovable">Will removing this engine not break your code?</param>
|
||||||
|
public SimpleEventEmitterEngine(int type, string name, bool isRemovable = true)
|
||||||
|
{
|
||||||
|
this.type = type;
|
||||||
|
this.Name = name;
|
||||||
|
this.isRemovable = isRemovable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
98
GamecraftModdingAPI/Events/SimpleEventHandlerEngine.cs
Normal file
98
GamecraftModdingAPI/Events/SimpleEventHandlerEngine.cs
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A simple implementation of IEventHandlerEngine sufficient for most uses
|
||||||
|
/// </summary>
|
||||||
|
public class SimpleEventHandlerEngine : IEventHandlerEngine
|
||||||
|
{
|
||||||
|
public int type { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
private bool isActivated = false;
|
||||||
|
|
||||||
|
private readonly Action<EntitiesDB> onActivated;
|
||||||
|
|
||||||
|
private readonly Action<EntitiesDB> onDestroyed;
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public void Add(ref ModEventEntityStruct entityView, EGID egid)
|
||||||
|
{
|
||||||
|
if (entityView.type.Equals(this.type))
|
||||||
|
{
|
||||||
|
isActivated = true;
|
||||||
|
onActivated.Invoke(entitiesDB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Manually activate the EventHandler.
|
||||||
|
/// Once activated, the next remove event will not be ignored.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle">Whether to invoke the activated action</param>
|
||||||
|
public void Activate(bool handle = false)
|
||||||
|
{
|
||||||
|
isActivated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready() { }
|
||||||
|
|
||||||
|
public void Remove(ref ModEventEntityStruct entityView, EGID egid)
|
||||||
|
{
|
||||||
|
if (entityView.type.Equals(this.type) && isActivated)
|
||||||
|
{
|
||||||
|
isActivated = false;
|
||||||
|
onDestroyed.Invoke(entitiesDB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (isActivated)
|
||||||
|
{
|
||||||
|
isActivated = false;
|
||||||
|
onDestroyed.Invoke(entitiesDB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Construct the engine
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="activated">The operation to do when the event is created</param>
|
||||||
|
/// <param name="removed">The operation to do when the event is destroyed (if applicable)</param>
|
||||||
|
/// <param name="type">The type of event to handle</param>
|
||||||
|
/// <param name="name">The name of the engine</param>
|
||||||
|
/// <param name="simple">A useless parameter to use to avoid Python overload resolution errors</param>
|
||||||
|
public SimpleEventHandlerEngine(Action activated, Action removed, int type, string name, bool simple = true)
|
||||||
|
: this((EntitiesDB _) => { activated.Invoke(); }, (EntitiesDB _) => { removed.Invoke(); }, type, name) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Construct the engine
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="activated">The operation to do when the event is created</param>
|
||||||
|
/// <param name="removed">The operation to do when the event is destroyed (if applicable)</param>
|
||||||
|
/// <param name="type">The type of event to handler</param>
|
||||||
|
/// <param name="name">The name of the engine</param>
|
||||||
|
public SimpleEventHandlerEngine(Action<EntitiesDB> activated, Action<EntitiesDB> removed, int type, string name)
|
||||||
|
{
|
||||||
|
this.type = type;
|
||||||
|
this.Name = name;
|
||||||
|
this.onActivated = activated;
|
||||||
|
this.onDestroyed = removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleEventHandlerEngine(Action activated, Action removed, EventType type, string name, bool simple = true)
|
||||||
|
: this((EntitiesDB _) => { activated.Invoke(); }, (EntitiesDB _) => { removed.Invoke(); }, (int)type, name) { }
|
||||||
|
|
||||||
|
public SimpleEventHandlerEngine(Action<EntitiesDB> activated, Action<EntitiesDB> removed, EventType type, string name, bool simple = true)
|
||||||
|
: this(activated, removed, (int)type, name) { }
|
||||||
|
}
|
||||||
|
}
|
518
GamecraftModdingAPI/GamecraftModdingAPI.csproj
Normal file
518
GamecraftModdingAPI/GamecraftModdingAPI.csproj
Normal file
|
@ -0,0 +1,518 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net472</TargetFramework>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<Version>0.2.2</Version>
|
||||||
|
<Authors>Exmods</Authors>
|
||||||
|
<PackageLicenseExpression>GNU General Public Licence 3+</PackageLicenseExpression>
|
||||||
|
<PackageProjectUrl>https://git.exmods.org/modtainers/GamecraftModdingAPI</PackageProjectUrl>
|
||||||
|
<NeutralLanguage>en-CA</NeutralLanguage>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Lib.Harmony" Version="1.2.0.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!--Start Dependencies-->
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Analytics">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Analytics.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Assembly-CSharp-firstpass">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Authentication">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Authentication.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="BlockEntityFactory">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\BlockEntityFactory.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="CommandLine">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\CommandLine.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="DataLoader">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\DataLoader.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="DDNA">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\DDNA.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Facepunch.Steamworks.Win64">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="FMOD">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\FMOD.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="FullGame">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\FullGame.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Gamecraft.Blocks.ConsoleBlock">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.ConsoleBlock.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Gamecraft.Effects">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Effects.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Gamecraft.GUI.GraphicsScreen">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.GraphicsScreen.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Gamecraft.GUI.Tweaks">
|
||||||
|
<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>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Gamecraft.Tweaks">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Gamecraft.Wires">
|
||||||
|
<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>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="GameState">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\GameState.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="GPUInstancer">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\GPUInstancer.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Havok.Physics">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Havok.Physics.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Havok.Physics.Hybrid">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Havok.Physics.Hybrid.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="IllusionInjector">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\IllusionInjector.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="IllusionPlugin">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\IllusionPlugin.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="JWT">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\JWT.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="LZ4">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\LZ4.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="MultiplayerNetworking">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\MultiplayerNetworking.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="MultiplayerTest">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\MultiplayerTest.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Newtonsoft.Json">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RCX.ScreenshotTaker">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RCX.ScreenshotTaker.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Rewired_Core">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Rewired_Core.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Rewired_Windows">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Rewired_Windows.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.AccountPreferences">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.AccountPreferences.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.Blocks">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Blocks.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.Blocks.Ghost">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Blocks.Ghost.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.Blocks.Triggers">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Blocks.Triggers.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.Character">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Character.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.Common">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Common.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.ControlsScreen">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.ControlsScreen.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.Crosshair">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Crosshair.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.FrontEnd">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.FrontEnd.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.GUI.DebugDisplay">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.DebugDisplay.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.GUI">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.GUI.RemoveBlock">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.RemoveBlock.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.GUI.ScaleGhost">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.ScaleGhost.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.GUIs.WorkshopPrefabs">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.GUIs.WorkshopPrefabs.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.Input">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Input.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.MachineEditor">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.MachineEditor.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.MainGame">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.MainGame.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.MainSimulation">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.MainSimulation.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.Multiplayer">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Multiplayer.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.Multiplayer.NetworkEntityStream">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Multiplayer.NetworkEntityStream.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.MultiplayerInput">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.MultiplayerInput.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.Party">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Party.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.PartyGui">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.PartyGui.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.Physics">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Physics.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.PilotSeat">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.PilotSeat.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.Player">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Player.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.Rendering">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Rendering.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.Rendering.Mock">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Rendering.Mock.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.SaveAndLoad">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.SaveAndLoad.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.SaveGameDialog">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.SaveGameDialog.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.Serializers">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Serializers.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.Services">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Services.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.SignalHandling">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.SignalHandling.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX.StateSync">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.StateSync.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX_SpawnPoints">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX_SpawnPoints.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocraftX_TextBlock">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX_TextBlock.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RobocratX.SimulationCompositionRoot">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\RobocratX.SimulationCompositionRoot.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="StringFormatter">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\StringFormatter.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Svelto.Common_3">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.Common_3.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Svelto.ECS.Debugger">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.ECS.Debugger.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Svelto.ECS">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.ECS.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Svelto.Services">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.Services.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Svelto.Tasks">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.Tasks.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Addressables">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Addressables.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Burst">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Burst.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Burst.Unsafe">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Burst.Unsafe.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Collections">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Collections.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Entities">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Entities.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Entities.Hybrid">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Entities.Hybrid.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Jobs">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Jobs.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Mathematics">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Mathematics.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Mathematics.Extensions">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Mathematics.Extensions.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Mathematics.Extensions.Hybrid">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Mathematics.Extensions.Hybrid.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Physics">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Physics.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Physics.Hybrid">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Physics.Hybrid.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Postprocessing.Runtime">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Postprocessing.Runtime.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Properties">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Properties.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.RenderPipelines.Core.Runtime">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.Core.Runtime.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.RenderPipelines.Core.ShaderLibrary">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.Core.ShaderLibrary.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.ResourceManager">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.ResourceManager.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Scenes.Hybrid">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Scenes.Hybrid.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.ScriptableBuildPipeline">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.ScriptableBuildPipeline.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.TextMeshPro">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.TextMeshPro.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Timeline">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Timeline.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Transforms">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Transforms.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.Transforms.Hybrid">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Transforms.Hybrid.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.AccessibilityModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AccessibilityModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.AIModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AIModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.AndroidJNIModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AndroidJNIModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.AnimationModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.ARModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ARModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.AssetBundleModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AssetBundleModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.AudioModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AudioModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.ClothModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ClothModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.ClusterInputModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterInputModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.ClusterRendererModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterRendererModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.CoreModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.CrashReportingModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.CrashReportingModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.DirectorModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.DirectorModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.DSPGraphModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.DSPGraphModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.GameCenterModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.GameCenterModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.GridModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.GridModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.HotReloadModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.HotReloadModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.ImageConversionModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ImageConversionModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.IMGUIModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.InputLegacyModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.InputModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.InputModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.JSONSerializeModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.JSONSerializeModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.LocalizationModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.LocalizationModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.ParticleSystemModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ParticleSystemModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.PerformanceReportingModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.PerformanceReportingModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.Physics2DModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.Physics2DModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.PhysicsModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.ProfilerModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ProfilerModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.ScreenCaptureModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ScreenCaptureModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.SharedInternalsModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SharedInternalsModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.SpriteMaskModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteMaskModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.SpriteShapeModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteShapeModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.StreamingModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.StreamingModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.SubstanceModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SubstanceModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.TerrainModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.TerrainPhysicsModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainPhysicsModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.TextCoreModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TextCoreModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.TextRenderingModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.TilemapModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TilemapModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.TLSModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TLSModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UI">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UI.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UIElementsModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UIElementsModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UIModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UIModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UmbraModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UmbraModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UNETModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UNETModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UnityAnalyticsModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityAnalyticsModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UnityConnectModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityConnectModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UnityTestProtocolModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityTestProtocolModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UnityWebRequestAssetBundleModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAssetBundleModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UnityWebRequestAudioModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UnityWebRequestModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UnityWebRequestTextureModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UnityWebRequestWWWModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.VehiclesModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VehiclesModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.VFXModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VFXModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.VideoModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VideoModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.VRModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VRModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.WindModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.WindModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.XRModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.XRModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="uREPL">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\uREPL.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="VisualProfiler">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\VisualProfiler.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.CoreModule">
|
||||||
|
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<!--End Dependencies-->
|
||||||
|
|
||||||
|
</Project>
|
153
GamecraftModdingAPI/Input/FakeInput.cs
Normal file
153
GamecraftModdingAPI/Input/FakeInput.cs
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.Common.Input;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Input
|
||||||
|
{
|
||||||
|
public static class FakeInput
|
||||||
|
{
|
||||||
|
private static readonly FakeInputEngine inputEngine = new FakeInputEngine();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Customize the player input.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">The custom input.</param>
|
||||||
|
/// <param name="playerID">The player. Omit this to use the local player.</param>
|
||||||
|
public static void CustomInput(InputEntityStruct input, uint playerID = uint.MaxValue)
|
||||||
|
{
|
||||||
|
if (playerID == uint.MaxValue)
|
||||||
|
{
|
||||||
|
playerID = inputEngine.GetLocalPlayerID();
|
||||||
|
}
|
||||||
|
inputEngine.SendCustomInput(input, playerID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InputEntityStruct GetInput(uint playerID = uint.MaxValue)
|
||||||
|
{
|
||||||
|
if (playerID == uint.MaxValue)
|
||||||
|
{
|
||||||
|
playerID = inputEngine.GetLocalPlayerID();
|
||||||
|
}
|
||||||
|
return inputEngine.GetInput(playerID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fake a GUI input.
|
||||||
|
/// Omit any parameter you do not want to affect.
|
||||||
|
/// Parameters that end with "?" don't do anything... yet.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="playerID">The player. Omit this to use the local player.</param>
|
||||||
|
/// <param name="hotbar">Select the hotbar slot by number.</param>
|
||||||
|
/// <param name="hotbarHand">Select the hotbar hand.</param>
|
||||||
|
/// <param name="commandLine">Toggle the command line?</param>
|
||||||
|
/// <param name="inventory">Open inventory?</param>
|
||||||
|
/// <param name="escape">Open escape menu?</param>
|
||||||
|
/// <param name="enter">Page return?</param>
|
||||||
|
/// <param name="debug">Toggle debug display?</param>
|
||||||
|
/// <param name="next">Select next?</param>
|
||||||
|
/// <param name="previous">Select previous?</param>
|
||||||
|
/// <param name="tab">Tab?</param>
|
||||||
|
/// <param name="colour">Toggle to hotbar colour mode?</param>
|
||||||
|
/// <param name="hotbarPage">Select the hotbar page by number?</param>
|
||||||
|
/// <param name="quickSave">Quicksave?</param>
|
||||||
|
/// <param name="paste">Paste?</param>
|
||||||
|
public static void GuiInput(uint playerID = uint.MaxValue, int hotbar = -1, bool hotbarHand = false, bool commandLine = false, bool inventory = false, bool escape = false, bool enter = false, bool debug = false, bool next = false, bool previous = false, bool tab = false, bool colour = false, int hotbarPage = -1, bool quickSave = false, bool paste = false)
|
||||||
|
{
|
||||||
|
if (playerID == uint.MaxValue)
|
||||||
|
{
|
||||||
|
playerID = inputEngine.GetLocalPlayerID();
|
||||||
|
}
|
||||||
|
ref InputEntityStruct currentInput = ref inputEngine.GetInputRef(playerID);
|
||||||
|
Utility.Logging.CommandLog($"Current sim frame {currentInput.frame}");
|
||||||
|
// set inputs
|
||||||
|
switch(hotbar)
|
||||||
|
{
|
||||||
|
case 0: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_0; break;
|
||||||
|
case 1: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_1; break;
|
||||||
|
case 2: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_2; break;
|
||||||
|
case 3: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_3; break;
|
||||||
|
case 4: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_4; break;
|
||||||
|
case 5: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_5; break;
|
||||||
|
case 6: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_6; break;
|
||||||
|
case 7: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_7; break;
|
||||||
|
case 8: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_8; break;
|
||||||
|
case 9: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_9; break;
|
||||||
|
case 10: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_Hand; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
if (hotbarHand) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_Hand;
|
||||||
|
if (commandLine) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.ToggleCommandLine;
|
||||||
|
if (inventory) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Inventory;
|
||||||
|
if (escape) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Escape;
|
||||||
|
if (enter) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Return;
|
||||||
|
if (debug) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.ToggleDebugDisplay;
|
||||||
|
if (next) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.SelectNext;
|
||||||
|
if (previous) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.SelectPrev;
|
||||||
|
if (tab) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Tab;
|
||||||
|
if (colour) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_Colour;
|
||||||
|
switch (hotbarPage)
|
||||||
|
{
|
||||||
|
case 1: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.HotbarPage1; break;
|
||||||
|
case 2: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.HotbarPage2; break;
|
||||||
|
case 3: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.HotbarPage3; break;
|
||||||
|
case 4: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.HotbarPage4; break;
|
||||||
|
case 5: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.HotbarPage5; break;
|
||||||
|
case 6: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.HotbarPage6; break;
|
||||||
|
case 7: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.HotbarPage7; break;
|
||||||
|
case 8: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.HotbarPage8; break;
|
||||||
|
case 9: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.HotbarPage9; break;
|
||||||
|
case 10: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.HotbarPage10; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
if (quickSave) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.QuickSave;
|
||||||
|
if (paste) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.PasteSelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ActionInput(uint playerID = uint.MaxValue, bool toggleMode = false, bool forward = false, bool backward = false, bool up = false, bool down = false, bool left = false, bool right = false, bool sprint = false, bool toggleFly = false, bool alt = false, bool primary = false, bool secondary = false, bool tertiary = false, bool primaryRelease = false, bool primaryHeld = false, bool secondaryHeld = false, bool toggleUnitGrid = false, bool ctrl = false, bool toggleColourMode = false, bool scaleBlockUp = false, bool scaleBlockDown = false, bool rotateBlockClockwise = false, bool rotateBlockCounterclockwise = false, bool cutSelection = false, bool copySelection = false, bool deleteSelection = false)
|
||||||
|
{
|
||||||
|
if (playerID == uint.MaxValue)
|
||||||
|
{
|
||||||
|
playerID = inputEngine.GetLocalPlayerID();
|
||||||
|
}
|
||||||
|
ref InputEntityStruct currentInput = ref inputEngine.GetInputRef(playerID);
|
||||||
|
Utility.Logging.CommandLog($"Current sim frame {currentInput.frame}");
|
||||||
|
// set inputs
|
||||||
|
if (toggleMode) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ToggleSimulation;
|
||||||
|
if (forward) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Forward;
|
||||||
|
if (backward) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Backward;
|
||||||
|
if (up) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Up;
|
||||||
|
if (down) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Down;
|
||||||
|
if (left) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Left;
|
||||||
|
if (right) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Right;
|
||||||
|
if (sprint) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Sprint;
|
||||||
|
if (toggleFly) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.SwitchFlyMode;
|
||||||
|
if (alt) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.AltAction;
|
||||||
|
if (primary) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.PrimaryAction;
|
||||||
|
if (secondary) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.SecondaryAction;
|
||||||
|
if (tertiary) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.TertiaryAction;
|
||||||
|
if (primaryRelease) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.PrimaryActionRelease;
|
||||||
|
if (primaryHeld) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.PrimaryActionHeld;
|
||||||
|
if (secondaryHeld) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.SecondaryActionHeld;
|
||||||
|
if (toggleUnitGrid) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ToggleUnitGrid;
|
||||||
|
if (ctrl) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.CtrlAction;
|
||||||
|
if (toggleColourMode) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ToggleColourMode;
|
||||||
|
if (scaleBlockUp) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ScaleBlockUp;
|
||||||
|
if (scaleBlockDown) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ScaleBlockDown;
|
||||||
|
if (rotateBlockClockwise) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.RotateBlockClockwise;
|
||||||
|
if (rotateBlockCounterclockwise) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.RotateBlockAnticlockwise;
|
||||||
|
if (cutSelection) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.CutSelection;
|
||||||
|
if (copySelection) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.CopySelection;
|
||||||
|
if (deleteSelection) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.DeleteSelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
GameEngineManager.AddGameEngine(inputEngine);
|
||||||
|
MenuEngineManager.AddMenuEngine(inputEngine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
62
GamecraftModdingAPI/Input/FakeInputEngine.cs
Normal file
62
GamecraftModdingAPI/Input/FakeInputEngine.cs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using RobocraftX.Common.Input;
|
||||||
|
using RobocraftX.Players;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Input
|
||||||
|
{
|
||||||
|
public class FakeInputEngine : IApiEngine
|
||||||
|
{
|
||||||
|
public string Name { get; } = "GamecraftModdingAPIFakeInputEngine";
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public bool IsReady = false;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
IsReady = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
IsReady = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SendCustomInput(InputEntityStruct input, uint playerID, bool remote = false)
|
||||||
|
{
|
||||||
|
EGID egid = new EGID(playerID, remote ? InputExclusiveGroups.RemotePlayers : InputExclusiveGroups.LocalPlayers);
|
||||||
|
if (entitiesDB.Exists<InputEntityStruct>(egid))
|
||||||
|
{
|
||||||
|
ref InputEntityStruct ies = ref entitiesDB.QueryEntity<InputEntityStruct>(egid);
|
||||||
|
ies = input;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputEntityStruct GetInput(uint playerID, bool remote = false)
|
||||||
|
{
|
||||||
|
EGID egid = new EGID(playerID, remote ? InputExclusiveGroups.RemotePlayers : InputExclusiveGroups.LocalPlayers);
|
||||||
|
if (entitiesDB.Exists<InputEntityStruct>(egid))
|
||||||
|
{
|
||||||
|
return entitiesDB.QueryEntity<InputEntityStruct>(egid);
|
||||||
|
}
|
||||||
|
else return default(InputEntityStruct);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref InputEntityStruct GetInputRef(uint playerID, bool remote = false)
|
||||||
|
{
|
||||||
|
EGID egid = new EGID(playerID, remote ? InputExclusiveGroups.RemotePlayers : InputExclusiveGroups.LocalPlayers);
|
||||||
|
return ref entitiesDB.QueryEntity<InputEntityStruct>(egid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint GetLocalPlayerID()
|
||||||
|
{
|
||||||
|
return LocalPlayerIDUtility.GetLocalPlayerID(entitiesDB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
GamecraftModdingAPI/Inventory/Hotbar.cs
Normal file
47
GamecraftModdingAPI/Inventory/Hotbar.cs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using RobocraftX.Common.Input;
|
||||||
|
using RobocraftX.Multiplayer.Input;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Blocks;
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
using Harmony;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Inventory
|
||||||
|
{
|
||||||
|
public static class Hotbar
|
||||||
|
{
|
||||||
|
private static readonly HotbarEngine hotbarEngine = new HotbarEngine();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Switch the block in the player's hand
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="block">The block to switch to.</param>
|
||||||
|
/// <param name="playerID">The player. Omit this to use the local player.</param>
|
||||||
|
public static void EquipBlock(BlockIDs block, uint playerID = uint.MaxValue)
|
||||||
|
{
|
||||||
|
if (playerID == uint.MaxValue)
|
||||||
|
{
|
||||||
|
playerID = hotbarEngine.GetLocalPlayerID();
|
||||||
|
}
|
||||||
|
hotbarEngine.SelectBlock((int) block, playerID);
|
||||||
|
// cubeSelectedByPick = true will crash the game
|
||||||
|
// (this would be equivalent to mouse middle click pick block action)
|
||||||
|
// reason: the game expects a Dictionary entry for the tweaked stats
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the block in the player's hand
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The equipped block.</returns>
|
||||||
|
public static BlockIDs GetEquippedBlock()
|
||||||
|
{
|
||||||
|
return HotbarSlotSelectionHandlerEnginePatch.EquippedPartID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
GameEngineManager.AddGameEngine(hotbarEngine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
GamecraftModdingAPI/Inventory/HotbarEngine.cs
Normal file
55
GamecraftModdingAPI/Inventory/HotbarEngine.cs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using RobocraftX.Character;
|
||||||
|
using RobocraftX.GUI.Hotbar;
|
||||||
|
using RobocraftX.Players;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.Common.Input;
|
||||||
|
using RobocraftX.Common.Players;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Blocks;
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Inventory
|
||||||
|
{
|
||||||
|
public class HotbarEngine : IApiEngine
|
||||||
|
{
|
||||||
|
public string Name { get; } = "GamecraftModdingAPIHotbarGameEngine";
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public bool IsInGame = false;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
IsInGame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
IsInGame = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SelectBlock(int block, uint playerID, bool cubeSelectedByPick = false)
|
||||||
|
{
|
||||||
|
InputEntityStruct[] inputs = entitiesDB.QueryEntities<InputEntityStruct>(InputExclusiveGroups.LocalPlayers).ToFastAccess(out uint count);
|
||||||
|
if (count == 0) return false;
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (inputs[i].ID.entityID == playerID) {
|
||||||
|
inputs[i].cubeSelectedByPick = cubeSelectedByPick;
|
||||||
|
inputs[i].selectedCube = block;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: expose the rest of the input functionality
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint GetLocalPlayerID()
|
||||||
|
{
|
||||||
|
return LocalPlayerIDUtility.GetLocalPlayerID(entitiesDB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using RobocraftX.GUI;
|
||||||
|
using RobocraftX.GUI.Hotbar;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using Harmony;
|
||||||
|
using GamecraftModdingAPI.Blocks;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Inventory
|
||||||
|
{
|
||||||
|
[HarmonyPatch]
|
||||||
|
public class HotbarSlotSelectionHandlerEnginePatch
|
||||||
|
{
|
||||||
|
private static int selectedBlockInt = 0;
|
||||||
|
|
||||||
|
public static BlockIDs EquippedPartID { get => (BlockIDs)selectedBlockInt; }
|
||||||
|
|
||||||
|
private static MethodInfo PatchedMethod { get; } = AccessTools.Method(AccessTools.TypeByName("RobocraftX.GUI.Hotbar.HotbarSlotSelectionHandlerEngine"), "HandleEquippedCubeChanged", parameters: new Type[] { typeof(uint), typeof(int), typeof(ExclusiveGroupStruct) });
|
||||||
|
|
||||||
|
public static void Prefix(uint playerID, int selectedDBPartID, ExclusiveGroupStruct groupID)
|
||||||
|
{
|
||||||
|
selectedBlockInt = selectedDBPartID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodBase TargetMethod(HarmonyInstance instance)
|
||||||
|
{
|
||||||
|
return PatchedMethod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
100
GamecraftModdingAPI/Main.cs
Normal file
100
GamecraftModdingAPI/Main.cs
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using Harmony;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
using GamecraftModdingAPI.Events;
|
||||||
|
using GamecraftModdingAPI.Tasks;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The main class of the GamecraftModdingAPI.
|
||||||
|
/// Use this to initialize the API before calling it.
|
||||||
|
/// </summary>
|
||||||
|
public static class Main
|
||||||
|
{
|
||||||
|
private static HarmonyInstance harmony;
|
||||||
|
|
||||||
|
public static bool IsInitialized {
|
||||||
|
get { return harmony != null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int referenceCount = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the GamecraftModdingAPI.
|
||||||
|
/// Call this as soon as possible after Gamecraft starts up.
|
||||||
|
/// Ideally, this should be called from your main Plugin class's OnApplicationStart() method.
|
||||||
|
/// </summary>
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
referenceCount++;
|
||||||
|
if (referenceCount > 1) { return; }
|
||||||
|
if (IsInitialized)
|
||||||
|
{
|
||||||
|
Logging.LogWarning("GamecraftModdingAPI.Main.Init() called but API is already initialized!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Logging.MetaDebugLog($"Patching Gamecraft");
|
||||||
|
var currentAssembly = Assembly.GetExecutingAssembly();
|
||||||
|
harmony = HarmonyInstance.Create(currentAssembly.GetName().Name);
|
||||||
|
harmony.PatchAll(currentAssembly);
|
||||||
|
// init utility
|
||||||
|
Logging.MetaDebugLog($"Initializing Utility");
|
||||||
|
Utility.GameState.Init();
|
||||||
|
Utility.VersionTracking.Init();
|
||||||
|
// create default event emitters
|
||||||
|
Logging.MetaDebugLog($"Initializing Events");
|
||||||
|
EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.ApplicationInitialized, "GamecraftModdingAPIApplicationInitializedEventEmitter", false));
|
||||||
|
EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.Menu, "GamecraftModdingAPIMenuActivatedEventEmitter", false));
|
||||||
|
EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.MenuSwitchedTo, "GamecraftModdingAPIMenuSwitchedToEventEmitter", false));
|
||||||
|
EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.Game, "GamecraftModdingAPIGameActivatedEventEmitter", false));
|
||||||
|
EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.GameReloaded, "GamecraftModdingAPIGameReloadedEventEmitter", false));
|
||||||
|
EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.GameSwitchedTo, "GamecraftModdingAPIGameSwitchedToEventEmitter", false));
|
||||||
|
EventManager.AddEventEmitter(GameHostTransitionDeterministicGroupEnginePatch.buildEngine);
|
||||||
|
EventManager.AddEventEmitter(GameHostTransitionDeterministicGroupEnginePatch.simEngine);
|
||||||
|
// init block implementors
|
||||||
|
Logging.MetaDebugLog($"Initializing Blocks");
|
||||||
|
Blocks.Movement.Init();
|
||||||
|
Blocks.Rotation.Init();
|
||||||
|
Blocks.Signals.Init();
|
||||||
|
Blocks.Placement.Init();
|
||||||
|
Blocks.Tweakable.Init();
|
||||||
|
Blocks.Removal.Init();
|
||||||
|
// init inventory
|
||||||
|
Inventory.Hotbar.Init();
|
||||||
|
// init input
|
||||||
|
Input.FakeInput.Init();
|
||||||
|
Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shuts down & cleans up the GamecraftModdingAPI.
|
||||||
|
/// Call this as late as possible before Gamecraft quits.
|
||||||
|
/// Ideally, this should be called from your main Plugin class's OnApplicationQuit() method.
|
||||||
|
/// </summary>
|
||||||
|
public static void Shutdown()
|
||||||
|
{
|
||||||
|
if (referenceCount > 0) { referenceCount--; }
|
||||||
|
if (referenceCount == 0)
|
||||||
|
{
|
||||||
|
if (!IsInitialized)
|
||||||
|
{
|
||||||
|
Logging.LogWarning("GamecraftModdingAPI.Main.Shutdown() called but API is not initialized!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Scheduler.Dispose();
|
||||||
|
var currentAssembly = Assembly.GetExecutingAssembly();
|
||||||
|
harmony.UnpatchAll(currentAssembly.GetName().Name);
|
||||||
|
harmony = null;
|
||||||
|
Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} shutdown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,26 +7,24 @@ using Svelto.DataStructures;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.Serialization;
|
using Svelto.ECS.Serialization;
|
||||||
|
|
||||||
using HarmonyLib;
|
using Harmony;
|
||||||
using TechbloxModdingAPI.Utility;
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Persistence
|
namespace GamecraftModdingAPI.Persistence
|
||||||
{
|
{
|
||||||
//[HarmonyPatch] - TODO
|
[HarmonyPatch]
|
||||||
class DeserializeFromDiskEntitiesEnginePatch
|
class DeserializeFromDiskEntitiesEnginePatch
|
||||||
{
|
{
|
||||||
internal static EntitiesDB entitiesDB = null;
|
internal static EntitiesDB entitiesDB = null;
|
||||||
|
|
||||||
private static readonly byte[] frameStart = Encoding.UTF8.GetBytes("\0\0\0TechbloxModdingAPI\0\0\0");
|
private static readonly byte[] frameStart = Encoding.UTF8.GetBytes("\0\0\0GamecraftModdingAPI\0\0\0");
|
||||||
|
|
||||||
public static void Prefix(ref ISerializationData ____serializationData, ref FasterList<byte> ____bytesStream, ref IEntitySerialization ____entitySerializer, bool ____spawnBlocksOnly)
|
public static void Prefix(ref ISerializationData ____serializationData, ref FasterList<byte> ____bytesStream, ref IEntitySerialization ____entitySerializer, bool ____spawnBlocksOnly)
|
||||||
{
|
{
|
||||||
if (____spawnBlocksOnly) return; // only run after second deserialization call (when all vanilla stuff is already deserialized)
|
if (____spawnBlocksOnly) return; // only run after second deserialization call (when all vanilla stuff is already deserialized)
|
||||||
if (SaveAndLoadCompositionRootPatch.currentEnginesRoot == null) return;
|
|
||||||
SerializerManager.RegisterSerializers(SaveAndLoadCompositionRootPatch.currentEnginesRoot);
|
|
||||||
uint originalPos = ____serializationData.dataPos;
|
uint originalPos = ____serializationData.dataPos;
|
||||||
Logging.MetaDebugLog($"dataPos: {originalPos}");
|
Logging.MetaDebugLog($"dataPos: {originalPos}");
|
||||||
BinaryBufferReader bbr = new BinaryBufferReader(____bytesStream.ToArrayFast(out int count), ____serializationData.dataPos);
|
BinaryBufferReader bbr = new BinaryBufferReader(____bytesStream.ToArrayFast(out uint count), ____serializationData.dataPos);
|
||||||
byte[] frameBuffer = new byte[frameStart.Length];
|
byte[] frameBuffer = new byte[frameStart.Length];
|
||||||
Logging.MetaDebugLog($"serial data count: {____serializationData.data.count} capacity: {____serializationData.data.capacity}");
|
Logging.MetaDebugLog($"serial data count: {____serializationData.data.count} capacity: {____serializationData.data.capacity}");
|
||||||
int i = 0;
|
int i = 0;
|
|
@ -3,16 +3,22 @@
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.Serialization;
|
using Svelto.ECS.Serialization;
|
||||||
|
|
||||||
using TechbloxModdingAPI.Utility;
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Persistence
|
namespace GamecraftModdingAPI.Persistence
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Entity serializer and deserializer interface for storing and retrieving data in a Techblox save file (GameSave.GC).
|
/// Entity serializer and deserializer interface for storing and retrieving data in a Gamecraft save file (GameSave.GC).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IEntitySerializer : IDeserializationFactory, IQueryingEntitiesEngine
|
public interface IEntitySerializer : IDeserializationFactory, IQueryingEntitiesEngine
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// The entity factory used for creating entities and entity components.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The entity factory.</value>
|
||||||
|
IEntityFactory EntityFactory { set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
/// Serialize the entities.
|
/// Serialize the entities.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Whether serialization was successful.</returns>
|
/// <returns>Whether serialization was successful.</returns>
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using RobocraftX.SaveAndLoad;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using Harmony;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Persistence
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(SaveAndLoadCompositionRoot), "Compose")]
|
||||||
|
class SaveAndLoadCompositionRootPatch
|
||||||
|
{
|
||||||
|
public static void Prefix(EnginesRoot enginesRoot)
|
||||||
|
{
|
||||||
|
SerializerManager.RegisterSerializers(enginesRoot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,15 +7,16 @@ using RobocraftX.SaveAndLoad;
|
||||||
using Svelto.DataStructures;
|
using Svelto.DataStructures;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.Serialization;
|
using Svelto.ECS.Serialization;
|
||||||
using HarmonyLib;
|
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Persistence
|
using GamecraftModdingAPI.Utility;
|
||||||
|
using Harmony;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Persistence
|
||||||
{
|
{
|
||||||
//[HarmonyPatch] - TODO
|
[HarmonyPatch]
|
||||||
class SaveGameEnginePatch
|
class SaveGameEnginePatch
|
||||||
{
|
{
|
||||||
private static readonly byte[] frameStart = Encoding.UTF8.GetBytes("\0\0\0TechbloxModdingAPI\0\0\0");
|
private static readonly byte[] frameStart = Encoding.UTF8.GetBytes("\0\0\0GamecraftModdingAPI\0\0\0");
|
||||||
|
|
||||||
public static void Postfix(ref ISerializationData serializationData, EntitiesDB entitiesDB, IEntitySerialization entitySerializer)
|
public static void Postfix(ref ISerializationData serializationData, EntitiesDB entitiesDB, IEntitySerialization entitySerializer)
|
||||||
{
|
{
|
||||||
|
@ -25,24 +26,24 @@ namespace TechbloxModdingAPI.Persistence
|
||||||
Logging.MetaDebugLog("Skipping component serialization: no serializers registered!");
|
Logging.MetaDebugLog("Skipping component serialization: no serializers registered!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
serializationData.data.IncreaseCapacityBy((uint)frameStart.Length);
|
serializationData.data.ExpandBy((uint)frameStart.Length);
|
||||||
BinaryBufferWriter bbw = new BinaryBufferWriter(serializationData.data.ToArrayFast(out int buffLen), serializationData.dataPos);
|
BinaryBufferWriter bbw = new BinaryBufferWriter(serializationData.data.ToArrayFast(out uint buffLen), serializationData.dataPos);
|
||||||
uint originalPos = serializationData.dataPos;
|
uint originalPos = serializationData.dataPos;
|
||||||
Logging.MetaDebugLog($"dataPos: {originalPos}");
|
Logging.MetaDebugLog($"dataPos: {originalPos}");
|
||||||
// Add frame start so it's easier to find TechbloxModdingAPI-serialized components
|
// Add frame start so it's easier to find GamecraftModdingAPI-serialized components
|
||||||
for (int i = 0; i < frameStart.Length; i++)
|
for (int i = 0; i < frameStart.Length; i++)
|
||||||
{
|
{
|
||||||
bbw.Write(frameStart[i]);
|
bbw.Write(frameStart[i]);
|
||||||
}
|
}
|
||||||
Logging.MetaDebugLog($"dataPos (after frame start): {bbw.Position}");
|
Logging.MetaDebugLog($"dataPos (after frame start): {bbw.Position}");
|
||||||
serializationData.data.IncreaseCapacityBy(4u);
|
serializationData.data.ExpandBy(4u);
|
||||||
bbw.Write((uint)SerializerManager.GetSerializersCount());
|
bbw.Write((uint)SerializerManager.GetSerializersCount());
|
||||||
string[] serializerKeys = SerializerManager.GetSerializerNames();
|
string[] serializerKeys = SerializerManager.GetSerializerNames();
|
||||||
for (uint c = 0; c < serializerKeys.Length; c++)
|
for (uint c = 0; c < serializerKeys.Length; c++)
|
||||||
{
|
{
|
||||||
Logging.MetaDebugLog($"dataPos (loop start): {bbw.Position}");
|
Logging.MetaDebugLog($"dataPos (loop start): {bbw.Position}");
|
||||||
// write component info
|
// write component info
|
||||||
serializationData.data.IncreaseCapacityBy(4u + (uint)serializerKeys[c].Length);
|
serializationData.data.ExpandBy(4u + (uint)serializerKeys[c].Length);
|
||||||
bbw.Write((uint)serializerKeys[c].Length);
|
bbw.Write((uint)serializerKeys[c].Length);
|
||||||
Logging.MetaDebugLog($"dataPos (now): {bbw.Position}");
|
Logging.MetaDebugLog($"dataPos (now): {bbw.Position}");
|
||||||
byte[] nameBytes = Encoding.UTF8.GetBytes(serializerKeys[c]);
|
byte[] nameBytes = Encoding.UTF8.GetBytes(serializerKeys[c]);
|
||||||
|
@ -51,7 +52,7 @@ namespace TechbloxModdingAPI.Persistence
|
||||||
bbw.Write(nameBytes[i]);
|
bbw.Write(nameBytes[i]);
|
||||||
}
|
}
|
||||||
Logging.MetaDebugLog($"dataPos (now): {bbw.Position}");
|
Logging.MetaDebugLog($"dataPos (now): {bbw.Position}");
|
||||||
serializationData.data.IncreaseCapacityBy(4u);
|
serializationData.data.ExpandBy(4u);
|
||||||
serializationData.dataPos = bbw.Position + 4u;
|
serializationData.dataPos = bbw.Position + 4u;
|
||||||
Logging.MetaDebugLog($"dataPos (now): {bbw.Position}");
|
Logging.MetaDebugLog($"dataPos (now): {bbw.Position}");
|
||||||
Logging.MetaDebugLog($"dataPos (appears to be): {serializationData.dataPos}");
|
Logging.MetaDebugLog($"dataPos (appears to be): {serializationData.dataPos}");
|
||||||
|
@ -73,8 +74,8 @@ namespace TechbloxModdingAPI.Persistence
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodBase TargetMethod()
|
public static MethodBase TargetMethod()
|
||||||
{
|
{
|
||||||
return AccessTools.TypeByName("RobocraftX.SaveAndLoad.SaveGameEngine").GetMethod("SerializeGameToBuffer");
|
return typeof(SaveGameEngine).GetMethod("SerializeGameToBuffer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,14 +4,15 @@ using System.Linq;
|
||||||
|
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.Serialization;
|
using Svelto.ECS.Serialization;
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Persistence
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Persistence
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Keeps track of serializers.
|
/// Keeps track of serializers.
|
||||||
/// This is used to add and retrieve serializers.
|
/// This is used to add and retrieve serializers.
|
||||||
/// Added IEntitySerializations are used in serializing and deserializing Techblox save files (GameSave.GC).
|
/// Added IEntitySerializations are used in serializing and deserializing Gamecraft save files (GameSave.GC).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class SerializerManager
|
public static class SerializerManager
|
||||||
{
|
{
|
||||||
|
@ -28,6 +29,7 @@ namespace TechbloxModdingAPI.Persistence
|
||||||
_registrations[name] = (IEntitySerialization ies) => { ies.RegisterSerializationFactory<T>(serializer); };
|
_registrations[name] = (IEntitySerialization ies) => { ies.RegisterSerializationFactory<T>(serializer); };
|
||||||
if (_lastEnginesRoot != null)
|
if (_lastEnginesRoot != null)
|
||||||
{
|
{
|
||||||
|
serializer.EntityFactory = _lastEnginesRoot.GenerateEntityFactory();
|
||||||
_registrations[name].Invoke(_lastEnginesRoot.GenerateEntitySerializer());
|
_registrations[name].Invoke(_lastEnginesRoot.GenerateEntitySerializer());
|
||||||
_lastEnginesRoot.AddEngine(serializer);
|
_lastEnginesRoot.AddEngine(serializer);
|
||||||
}
|
}
|
||||||
|
@ -58,13 +60,15 @@ namespace TechbloxModdingAPI.Persistence
|
||||||
return _serializers.Count;
|
return _serializers.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void RegisterSerializers(EnginesRoot enginesRoot)
|
public static void RegisterSerializers(EnginesRoot enginesRoot)
|
||||||
{
|
{
|
||||||
_lastEnginesRoot = enginesRoot;
|
_lastEnginesRoot = enginesRoot;
|
||||||
|
IEntityFactory factory = enginesRoot.GenerateEntityFactory();
|
||||||
IEntitySerialization ies = enginesRoot.GenerateEntitySerializer();
|
IEntitySerialization ies = enginesRoot.GenerateEntitySerializer();
|
||||||
foreach (string key in _serializers.Keys)
|
foreach (string key in _serializers.Keys)
|
||||||
{
|
{
|
||||||
Logging.MetaDebugLog($"Registering IEntitySerializer for {key}");
|
Logging.MetaDebugLog($"Registering IEntitySerializer for {key}");
|
||||||
|
_serializers[key].EntityFactory = factory;
|
||||||
_registrations[key].Invoke(ies);
|
_registrations[key].Invoke(ies);
|
||||||
enginesRoot.AddEngine(_serializers[key]);
|
enginesRoot.AddEngine(_serializers[key]);
|
||||||
}
|
}
|
|
@ -5,7 +5,7 @@ using Svelto.ECS.Serialization;
|
||||||
|
|
||||||
using RobocraftX.Common;
|
using RobocraftX.Common;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Persistence
|
namespace GamecraftModdingAPI.Persistence
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Simple entity serializer sufficient for simple entity components.
|
/// Simple entity serializer sufficient for simple entity components.
|
||||||
|
@ -21,18 +21,20 @@ namespace TechbloxModdingAPI.Persistence
|
||||||
|
|
||||||
protected int serializationType;
|
protected int serializationType;
|
||||||
|
|
||||||
|
public IEntityFactory EntityFactory { set; protected get; }
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { set; protected get; }
|
public EntitiesDB entitiesDB { set; protected get; }
|
||||||
|
|
||||||
public EntityInitializer BuildDeserializedEntity(EGID egid, ISerializationData serializationData, ISerializableEntityDescriptor entityDescriptor, int serializationType, IEntitySerialization entitySerialization, IEntityFactory factory, bool enginesRootIsDeserializationOnly)
|
public EntityComponentInitializer BuildDeserializedEntity(EGID egid, ISerializationData serializationData, ISerializableEntityDescriptor entityDescriptor, int serializationType, IEntitySerialization entitySerialization)
|
||||||
{
|
{
|
||||||
EntityInitializer esi = factory.BuildEntity<Descriptor>(egid);
|
EntityComponentInitializer esi = EntityFactory.BuildEntity<Descriptor>(egid);
|
||||||
entitySerialization.DeserializeEntityComponents(serializationData, entityDescriptor, ref esi, serializationType);
|
entitySerialization.DeserializeEntityComponents(serializationData, entityDescriptor, ref esi, serializationType);
|
||||||
return esi;
|
return esi;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Deserialize(ref ISerializationData serializationData, IEntitySerialization entitySerializer)
|
public bool Deserialize(ref ISerializationData serializationData, IEntitySerialization entitySerializer)
|
||||||
{
|
{
|
||||||
BinaryBufferReader bbr = new BinaryBufferReader(serializationData.data.ToArrayFast(out int count), serializationData.dataPos);
|
BinaryBufferReader bbr = new BinaryBufferReader(serializationData.data.ToArrayFast(out uint count), serializationData.dataPos);
|
||||||
uint entityCount = bbr.ReadUint();
|
uint entityCount = bbr.ReadUint();
|
||||||
serializationData.dataPos = bbr.Position;
|
serializationData.dataPos = bbr.Position;
|
||||||
for (uint i = 0; i < entityCount; i++)
|
for (uint i = 0; i < entityCount; i++)
|
||||||
|
@ -46,8 +48,8 @@ namespace TechbloxModdingAPI.Persistence
|
||||||
|
|
||||||
public bool Serialize(ref ISerializationData serializationData, EntitiesDB entitiesDB, IEntitySerialization entitySerializer)
|
public bool Serialize(ref ISerializationData serializationData, EntitiesDB entitiesDB, IEntitySerialization entitySerializer)
|
||||||
{
|
{
|
||||||
serializationData.data.IncreaseCapacityBy(4u);
|
serializationData.data.ExpandBy(4u);
|
||||||
BinaryBufferWriter bbw = new BinaryBufferWriter(serializationData.data.ToArrayFast(out int count), serializationData.dataPos);
|
BinaryBufferWriter bbw = new BinaryBufferWriter(serializationData.data.ToArrayFast(out uint count), serializationData.dataPos);
|
||||||
EGID[] toSerialize = getEntitiesToSerialize(entitiesDB);
|
EGID[] toSerialize = getEntitiesToSerialize(entitiesDB);
|
||||||
bbw.Write((uint)toSerialize.Length);
|
bbw.Write((uint)toSerialize.Length);
|
||||||
serializationData.dataPos = bbw.Position;
|
serializationData.dataPos = bbw.Position;
|
|
@ -6,7 +6,7 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
using Svelto.Tasks;
|
using Svelto.Tasks;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Tasks
|
namespace GamecraftModdingAPI.Tasks
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interface for asynchronous tasks
|
/// Interface for asynchronous tasks
|
|
@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||||
using Svelto.Tasks;
|
using Svelto.Tasks;
|
||||||
using Svelto.Tasks.Enumerators;
|
using Svelto.Tasks.Enumerators;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Tasks
|
namespace GamecraftModdingAPI.Tasks
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An asynchronous task to be performed once.
|
/// An asynchronous task to be performed once.
|
|
@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||||
using Svelto.Tasks;
|
using Svelto.Tasks;
|
||||||
using Svelto.Tasks.Enumerators;
|
using Svelto.Tasks.Enumerators;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Tasks
|
namespace GamecraftModdingAPI.Tasks
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An asynchronous repeating task.
|
/// An asynchronous repeating task.
|
|
@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||||
using Svelto.Tasks.Lean;
|
using Svelto.Tasks.Lean;
|
||||||
using Svelto.Tasks.ExtraLean;
|
using Svelto.Tasks.ExtraLean;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Tasks
|
namespace GamecraftModdingAPI.Tasks
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Asynchronous task scheduling for ISchedulables.
|
/// Asynchronous task scheduling for ISchedulables.
|
||||||
|
@ -20,7 +20,7 @@ namespace TechbloxModdingAPI.Tasks
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return RobocraftX.Schedulers.ClientLean.UIScheduler;
|
return RobocraftX.Schedulers.Lean.UIScheduler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,13 +28,13 @@ namespace TechbloxModdingAPI.Tasks
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return RobocraftX.Schedulers.ClientExtraLean.UIScheduler;
|
return RobocraftX.Schedulers.ExtraLean.UIScheduler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly Svelto.Tasks.ExtraLean.Unity.UpdateMonoRunner extraLeanRunner = new Svelto.Tasks.ExtraLean.Unity.UpdateMonoRunner("TechbloxModdingAPIExtraLean");
|
public static readonly Svelto.Tasks.ExtraLean.Unity.UpdateMonoRunner extraLeanRunner = new Svelto.Tasks.ExtraLean.Unity.UpdateMonoRunner("GamecraftModdingAPIExtraLean");
|
||||||
|
|
||||||
public static readonly Svelto.Tasks.Lean.Unity.UpdateMonoRunner leanRunner = new Svelto.Tasks.Lean.Unity.UpdateMonoRunner("TechbloxModdingAPILean");
|
public static readonly Svelto.Tasks.Lean.Unity.UpdateMonoRunner leanRunner = new Svelto.Tasks.Lean.Unity.UpdateMonoRunner("GamecraftModdingAPILean");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Schedule a task to run asynchronously.
|
/// Schedule a task to run asynchronously.
|
||||||
|
@ -42,7 +42,7 @@ namespace TechbloxModdingAPI.Tasks
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="toRun">The task to run</param>
|
/// <param name="toRun">The task to run</param>
|
||||||
/// <param name="extraLean">Schedule toRun on an extra lean runner?</param>
|
/// <param name="extraLean">Schedule toRun on an extra lean runner?</param>
|
||||||
/// <param name="ui">Schedule toRun on Techblox's built-in UI task runner?</param>
|
/// <param name="ui">Schedule toRun on Gamecraft's built-in UI task runner?</param>
|
||||||
public static void Schedule(ISchedulable toRun, bool extraLean = false, bool ui = false)
|
public static void Schedule(ISchedulable toRun, bool extraLean = false, bool ui = false)
|
||||||
{
|
{
|
||||||
if (extraLean)
|
if (extraLean)
|
153
GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs
Normal file
153
GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using Harmony;
|
||||||
|
// test
|
||||||
|
using Svelto.ECS;
|
||||||
|
using RobocraftX.Blocks;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.SimulationModeState;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Commands;
|
||||||
|
using GamecraftModdingAPI.Events;
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Tests
|
||||||
|
{
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
private static HarmonyInstance harmony { get; set; }
|
||||||
|
|
||||||
|
public string[] Filter { get; } = new string[] { "Gamecraft", "GamecraftPreview" };
|
||||||
|
|
||||||
|
public string Name { get; } = Assembly.GetExecutingAssembly().GetName().Name;
|
||||||
|
|
||||||
|
public string Version { get; } = Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||||
|
|
||||||
|
public string HarmonyID { get; } = "org.git.exmods.modtainers.gamecraftmoddingapi";
|
||||||
|
|
||||||
|
public void OnApplicationQuit()
|
||||||
|
{
|
||||||
|
GamecraftModdingAPI.Main.Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnApplicationStart()
|
||||||
|
{
|
||||||
|
FileLog.Reset();
|
||||||
|
HarmonyInstance.DEBUG = true;
|
||||||
|
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
|
||||||
|
//SteamInitPatch.ForcePassSteamCheck = true;
|
||||||
|
// in case running in a VM
|
||||||
|
//MinimumSpecsCheckPatch.ForcePassMinimumSpecCheck = true;
|
||||||
|
// disable some Gamecraft analytics
|
||||||
|
//AnalyticsDisablerPatch.DisableAnalytics = true;
|
||||||
|
// disable background music
|
||||||
|
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();
|
||||||
|
|
||||||
|
// debug/test handlers
|
||||||
|
EventManager.AddEventHandler(new SimpleEventHandlerEngine(() => { Logging.Log("App Inited event!"); }, () => { },
|
||||||
|
EventType.ApplicationInitialized, "appinit API debug"));
|
||||||
|
EventManager.AddEventHandler(new SimpleEventHandlerEngine(() => { Logging.Log("Menu Activated event!"); },
|
||||||
|
() => { Logging.Log("Menu Destroyed event!"); },
|
||||||
|
EventType.Menu, "menuact API debug"));
|
||||||
|
EventManager.AddEventHandler(new SimpleEventHandlerEngine(() => { Logging.Log("Menu Switched To event!"); }, () => { },
|
||||||
|
EventType.MenuSwitchedTo, "menuswitch API debug"));
|
||||||
|
EventManager.AddEventHandler(new SimpleEventHandlerEngine(() => { Logging.Log("Game Activated event!"); },
|
||||||
|
() => { Logging.Log("Game Destroyed event!"); },
|
||||||
|
EventType.Game, "gameact API debug"));
|
||||||
|
EventManager.AddEventHandler(new SimpleEventHandlerEngine(() => { Logging.Log("Game Reloaded event!"); }, () => { },
|
||||||
|
EventType.GameReloaded, "gamerel API debug"));
|
||||||
|
EventManager.AddEventHandler(new SimpleEventHandlerEngine(() => { Logging.Log("Game Switched To event!"); }, () => { },
|
||||||
|
EventType.GameSwitchedTo, "gameswitch API debug"));
|
||||||
|
EventManager.AddEventHandler(new SimpleEventHandlerEngine(() => { Logging.Log("Game Mode Simulation Switched To event!"); }, () => { },
|
||||||
|
EventType.SimulationSwitchedTo, "simulationswitch API debug"));
|
||||||
|
EventManager.AddEventHandler(new SimpleEventHandlerEngine(() => { Logging.Log("Game Mode Build Switched To event!"); }, () => { },
|
||||||
|
EventType.BuildSwitchedTo, "buildswitch API debug"));
|
||||||
|
|
||||||
|
// debug/test commands
|
||||||
|
if (Dependency.Hell("ExtraCommands"))
|
||||||
|
{
|
||||||
|
CommandManager.AddCommand(new SimpleCustomCommandEngine(() => { UnityEngine.Application.Quit(); },
|
||||||
|
"Exit", "Close Gamecraft without any prompts"));
|
||||||
|
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>(
|
||||||
|
(x, y, z) => {
|
||||||
|
bool success = GamecraftModdingAPI.Blocks.Movement.MoveConnectedBlocks(
|
||||||
|
GamecraftModdingAPI.Blocks.BlockIdentifiers.LatestBlockID,
|
||||||
|
new Unity.Mathematics.float3(x, y, z));
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
GamecraftModdingAPI.Utility.Logging.CommandLogError("Blocks can only be moved in Build mode!");
|
||||||
|
}
|
||||||
|
}, "MoveLastBlock", "Move the most-recently-placed block, and any connected blocks by the given offset"));
|
||||||
|
CommandManager.AddCommand(new SimpleCustomCommandEngine<float, float, float>(
|
||||||
|
(x, y, z) => { Blocks.Placement.PlaceBlock(Blocks.BlockIDs.AluminiumCube, new Unity.Mathematics.float3(x, y, z)); },
|
||||||
|
"PlaceAluminium", "Place a block of aluminium at the given coordinates"));
|
||||||
|
Analytics.DeltaDNAHelper.PlayerLifetimeParameters plp = new Analytics.DeltaDNAHelper.PlayerLifetimeParameters();
|
||||||
|
CommandManager.AddCommand(new SimpleCustomCommandEngine<string>(
|
||||||
|
(s) => { Analytics.DeltaDNAHelper.SendActionCompletedEvent(in plp, s.Replace(", ", " ")); },
|
||||||
|
"SendAnalyticsAction", "Send an analytics action"));
|
||||||
|
System.Random random = new System.Random(); // for command below
|
||||||
|
CommandManager.AddCommand(new SimpleCustomCommandEngine(
|
||||||
|
() => {
|
||||||
|
if (!GameState.IsSimulationMode())
|
||||||
|
{
|
||||||
|
Logging.CommandLogError("You must be in simulation mode for this to work!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Tasks.Repeatable task = new Tasks.Repeatable(() => {
|
||||||
|
uint count = 0;
|
||||||
|
EGID[] eBlocks = Blocks.Signals.GetElectricBlocks();
|
||||||
|
for (uint i = 0u; i < eBlocks.Length; i++)
|
||||||
|
{
|
||||||
|
uint[] ids = Blocks.Signals.GetSignalIDs(eBlocks[i]);
|
||||||
|
for (uint j = 0u; j < ids.Length; j++)
|
||||||
|
{
|
||||||
|
Blocks.Signals.SetSignalByID(ids[j], (float)random.NextDouble());
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Logging.MetaDebugLog($"Did the thing on {count} inputs");
|
||||||
|
},
|
||||||
|
() => { return GameState.IsSimulationMode(); });
|
||||||
|
Tasks.Scheduler.Schedule(task);
|
||||||
|
}, "RandomizeSignalsInputs", "Do the thing"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// dependency test
|
||||||
|
if (Dependency.Hell("GamecraftScripting", new Version("0.0.1.0")))
|
||||||
|
{
|
||||||
|
Logging.LogWarning("You're in GamecraftScripting dependency hell");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Log("Compatible GamecraftScripting detected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnFixedUpdate() { }
|
||||||
|
|
||||||
|
public void OnLateUpdate() { }
|
||||||
|
|
||||||
|
public void OnLevelWasInitialized(int level) { }
|
||||||
|
|
||||||
|
public void OnLevelWasLoaded(int level) { }
|
||||||
|
|
||||||
|
public void OnUpdate() { }
|
||||||
|
}
|
||||||
|
}
|
38
GamecraftModdingAPI/Utility/AnalyticsDisablerPatch.cs
Normal file
38
GamecraftModdingAPI/Utility/AnalyticsDisablerPatch.cs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using Analytics;
|
||||||
|
using Harmony;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Utility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Patch of Analytics.AnalyticsCompositionRoot.Compose<T>(...)
|
||||||
|
/// This stops some analytics collection built into Gamecraft.
|
||||||
|
/// DO NOT USE! (This will likely crash your game on shutdown)
|
||||||
|
/// </summary>
|
||||||
|
[HarmonyPatch]
|
||||||
|
class AnalyticsDisablerPatch
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Don't activate gameplay analytics?
|
||||||
|
/// </summary>
|
||||||
|
public static bool DisableAnalytics = false;
|
||||||
|
|
||||||
|
public static bool Prefix(object contextHolder, EnginesRoot enginesRoot, RCXMode rcxMode)
|
||||||
|
{
|
||||||
|
return !DisableAnalytics;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodBase TargetMethod(HarmonyInstance instance)
|
||||||
|
{
|
||||||
|
return typeof(Analytics.AnalyticsCompositionRoot).GetMethod("Compose").MakeGenericMethod(typeof(object));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
GamecraftModdingAPI/Utility/ApiExclusiveGroups.cs
Normal file
19
GamecraftModdingAPI/Utility/ApiExclusiveGroups.cs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Utility
|
||||||
|
{
|
||||||
|
public static class ApiExclusiveGroups
|
||||||
|
{
|
||||||
|
public static readonly ExclusiveGroup eventsExclusiveGroup = new ExclusiveGroup();
|
||||||
|
|
||||||
|
public static uint eventID;
|
||||||
|
|
||||||
|
public static readonly ExclusiveGroup versionGroup = new ExclusiveGroup("GamecraftModdingAPIVersion");
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||||
using FMODUnity;
|
using FMODUnity;
|
||||||
using FMOD.Studio;
|
using FMOD.Studio;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Utility
|
namespace GamecraftModdingAPI.Utility
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Common operations on audio objects
|
/// Common operations on audio objects
|
79
GamecraftModdingAPI/Utility/Dependency.cs
Normal file
79
GamecraftModdingAPI/Utility/Dependency.cs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using IllusionInjector;
|
||||||
|
using IllusionPlugin;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Utility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Simple plugin interaction operations
|
||||||
|
/// </summary>
|
||||||
|
public static class Dependency
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Find a plugin by name
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The plugin.</returns>
|
||||||
|
/// <param name="name">The plugin's name.</param>
|
||||||
|
public static IPlugin GetPlugin(string name)
|
||||||
|
{
|
||||||
|
foreach(IPlugin plugin in PluginManager.Plugins)
|
||||||
|
{
|
||||||
|
if (plugin.Name == name)
|
||||||
|
{
|
||||||
|
return plugin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the plugin version.
|
||||||
|
/// This gives priority to the plugin's Version string but falls back to the Assembly's version
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The plugin's version.</returns>
|
||||||
|
/// <param name="name">The plugin's name.</param>
|
||||||
|
public static Version GetPluginVersion(string name)
|
||||||
|
{
|
||||||
|
IPlugin plugin = GetPlugin(name);
|
||||||
|
if (plugin != null) {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new Version(plugin.Version);
|
||||||
|
} catch (Exception e) when (
|
||||||
|
e is ArgumentException
|
||||||
|
|| e is ArgumentNullException
|
||||||
|
|| e is ArgumentOutOfRangeException
|
||||||
|
|| e is FormatException
|
||||||
|
|| e is OverflowException) {}
|
||||||
|
return plugin.GetType().Assembly.GetName().Version;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (I'm leaving the auto-generated version)
|
||||||
|
// <summary>
|
||||||
|
// Hell the specified name and version.
|
||||||
|
// </summary>
|
||||||
|
// <returns>The hell.</returns>
|
||||||
|
// <param name="name">Name.</param>
|
||||||
|
// <param name="version">Version.</param>
|
||||||
|
/// <summary>
|
||||||
|
/// Detect if you're in dependency hell with respect to the plugin.
|
||||||
|
/// ie Check if the plugin doesn't exist or is out of date.
|
||||||
|
/// When version is null, this only checks if the plugin exists.
|
||||||
|
/// The version is retrieved using GetPluginVersion(string name).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Are you in dependency hell?</returns>
|
||||||
|
/// <param name="name">The plugin's name'</param>
|
||||||
|
/// <param name="version">The target version.</param>
|
||||||
|
public static bool Hell(string name, Version version = null)
|
||||||
|
{
|
||||||
|
Version pluginVersion = GetPluginVersion(name);
|
||||||
|
if (version == null) {
|
||||||
|
return pluginVersion == null;
|
||||||
|
}
|
||||||
|
return (pluginVersion == null || pluginVersion < version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,34 +1,32 @@
|
||||||
using DataLoader;
|
using System;
|
||||||
using HarmonyLib;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using DataLoader;
|
||||||
|
using Harmony;
|
||||||
using RobocraftX;
|
using RobocraftX;
|
||||||
using RobocraftX.CR.MainGame;
|
using RobocraftX.Common.Utilities;
|
||||||
using RobocraftX.GUI;
|
using RobocraftX.GUI;
|
||||||
using RobocraftX.Multiplayer;
|
using RobocraftX.Multiplayer;
|
||||||
|
using RobocraftX.Rendering;
|
||||||
using Svelto.Context;
|
using Svelto.Context;
|
||||||
using Svelto.DataStructures;
|
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.GUI;
|
using Svelto.ECS.Schedulers.Unity;
|
||||||
using Techblox.GameSelection;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Unity.Entities;
|
using Unity.Entities;
|
||||||
using Unity.Physics.Systems;
|
using Unity.Physics.Systems;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Utility
|
namespace GamecraftModdingAPI.Utility
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Public access to the private variables in RobocraftX.FullGameCompositionRoot
|
/// Public access to the private variables in RobocraftX.FullGameCompositionRoot
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class FullGameFields
|
public static class FullGameFields
|
||||||
{
|
{
|
||||||
public static FullGameCompositionRoot Instance
|
|
||||||
{
|
|
||||||
private set;
|
|
||||||
get;
|
|
||||||
} = null;
|
|
||||||
|
|
||||||
public static MultiplayerInitParameters _multiplayerParams
|
public static MultiplayerInitParameters _multiplayerParams
|
||||||
{
|
{ get
|
||||||
get
|
|
||||||
{
|
{
|
||||||
return (MultiplayerInitParameters)fgcr?.Field("_multiplayerParams").GetValue();
|
return (MultiplayerInitParameters)fgcr?.Field("_multiplayerParams").GetValue();
|
||||||
}
|
}
|
||||||
|
@ -66,6 +64,14 @@ namespace TechbloxModdingAPI.Utility
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SimpleEntitiesSubmissionScheduler _mainGameSubmissionScheduler
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (SimpleEntitiesSubmissionScheduler)fgcr?.Field("_sub").Field("_mainGameSubmissionScheduler").GetValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static BuildPhysicsWorld _physicsWorldSystem
|
public static BuildPhysicsWorld _physicsWorldSystem
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -98,6 +104,14 @@ namespace TechbloxModdingAPI.Utility
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PhysicsUtility _physicsUtility
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (PhysicsUtility)fgcr?.Field("_physicsUtility").GetValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*public static UnityEntitySubmissionScheduler _frontEndSubmissionScheduler
|
/*public static UnityEntitySubmissionScheduler _frontEndSubmissionScheduler
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -122,11 +136,11 @@ namespace TechbloxModdingAPI.Utility
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ECSMainGameResourceManagers _managers
|
public static ECSGameObjectResourceManager _eCsGameObjectResourceManager
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return (ECSMainGameResourceManagers)fgcr?.Field("_gameManagers").GetValue();
|
return (ECSGameObjectResourceManager)fgcr?.Field("_eCsGameObjectResourceManager").GetValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,36 +152,11 @@ namespace TechbloxModdingAPI.Utility
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FasterList<EGID> _deserialisedBlockMap
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return (FasterList<EGID>) fgcr?.Field("_deserialisedBlockMap").GetValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SveltoGUI _frontEndGUI
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return (SveltoGUI)fgcr?.Field("_frontEndGUI").GetValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GameSelectionData _gameSelectionData
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return (GameSelectionData)fgcr?.Field("_gameSelectionData").GetValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Traverse fgcr;
|
private static Traverse fgcr;
|
||||||
|
|
||||||
public static void Init(FullGameCompositionRoot instance)
|
public static void Init(FullGameCompositionRoot instance)
|
||||||
{
|
{
|
||||||
fgcr = new Traverse(instance);
|
fgcr = new Traverse(instance);
|
||||||
FullGameFields.Instance = instance;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,11 +1,12 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using RobocraftX.StateSync;
|
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using TechbloxModdingAPI.Engines;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Utility
|
namespace GamecraftModdingAPI.Utility
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Keeps track of custom game-modifying engines
|
/// Keeps track of custom game-modifying engines
|
||||||
|
@ -23,10 +24,6 @@ namespace TechbloxModdingAPI.Utility
|
||||||
{
|
{
|
||||||
Logging.MetaDebugLog($"Registering Game IApiEngine {engine.Name}");
|
Logging.MetaDebugLog($"Registering Game IApiEngine {engine.Name}");
|
||||||
_lastEngineRoot.AddEngine(engine);
|
_lastEngineRoot.AddEngine(engine);
|
||||||
if (engine is IFactoryEngine factoryEngine)
|
|
||||||
factoryEngine.Factory = _lastEngineRoot.GenerateEntityFactory();
|
|
||||||
if (engine is IFunEngine funEngine)
|
|
||||||
funEngine.Functions = _lastEngineRoot.GenerateEntityFunctions();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,29 +49,16 @@ namespace TechbloxModdingAPI.Utility
|
||||||
|
|
||||||
public static void RemoveGameEngine(string name)
|
public static void RemoveGameEngine(string name)
|
||||||
{
|
{
|
||||||
if (_gameEngines[name].isRemovable)
|
_gameEngines.Remove(name);
|
||||||
{
|
|
||||||
_gameEngines.Remove(name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RegisterEngines(StateSyncRegistrationHelper helper)
|
public static void RegisterEngines(EnginesRoot enginesRoot)
|
||||||
{
|
{
|
||||||
var enginesRoot = helper.enginesRoot;
|
|
||||||
_lastEngineRoot = enginesRoot;
|
_lastEngineRoot = enginesRoot;
|
||||||
IEntityFactory factory = enginesRoot.GenerateEntityFactory();
|
|
||||||
IEntityFunctions functions = enginesRoot.GenerateEntityFunctions();
|
|
||||||
foreach (var key in _gameEngines.Keys)
|
foreach (var key in _gameEngines.Keys)
|
||||||
{
|
{
|
||||||
Logging.MetaDebugLog($"Registering Game IApiEngine {_gameEngines[key].Name}");
|
Logging.MetaDebugLog($"Registering Game IApiEngine {_gameEngines[key].Name}");
|
||||||
if (_gameEngines[key] is IDeterministicEngine detEngine)
|
enginesRoot.AddEngine(_gameEngines[key]);
|
||||||
helper.AddDeterministicEngine(detEngine);
|
|
||||||
else
|
|
||||||
enginesRoot.AddEngine(_gameEngines[key]);
|
|
||||||
if (_gameEngines[key] is IFactoryEngine factEngine)
|
|
||||||
factEngine.Factory = factory;
|
|
||||||
if (_gameEngines[key] is IFunEngine funEngine)
|
|
||||||
funEngine.Functions = functions;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,10 +4,10 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Utility
|
namespace GamecraftModdingAPI.Utility
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Utility to get the state of the current Techblox game
|
/// Utility to get the state of the current Gamecraft game
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class GameState
|
public static class GameState
|
||||||
{
|
{
|
||||||
|
@ -34,7 +34,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is a game loaded?
|
/// Is a game loaded?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Whether Techblox has a game open (false = Main Menu)</returns>
|
/// <returns>Whether Gamecraft has a game open (false = Main Menu)</returns>
|
||||||
public static bool IsInGame()
|
public static bool IsInGame()
|
||||||
{
|
{
|
||||||
return gameEngine.IsInGame;
|
return gameEngine.IsInGame;
|
|
@ -6,13 +6,12 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using RobocraftX.SimulationModeState;
|
using RobocraftX.SimulationModeState;
|
||||||
using TechbloxModdingAPI.Engines;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Utility
|
namespace GamecraftModdingAPI.Utility
|
||||||
{
|
{
|
||||||
class GameStateEngine : IApiEngine
|
class GameStateEngine : IApiEngine
|
||||||
{
|
{
|
||||||
public string Name { get; } = "TechbloxModdingAPIGameStateGameEngine";
|
public string Name { get; } = "GamecraftModdingAPIGameStateGameEngine";
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { set; private get; }
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
@ -20,9 +19,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
|
|
||||||
public bool IsInGame { get { return _isInGame; } }
|
public bool IsInGame { get { return _isInGame; } }
|
||||||
|
|
||||||
public bool isRemovable => false;
|
public void Dispose()
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
{
|
||||||
_isInGame = false;
|
_isInGame = false;
|
||||||
}
|
}
|
||||||
|
@ -34,12 +31,12 @@ namespace TechbloxModdingAPI.Utility
|
||||||
|
|
||||||
public bool IsBuildMode()
|
public bool IsBuildMode()
|
||||||
{
|
{
|
||||||
return _isInGame && TimeRunningModeUtil.IsTimeStoppedMode(entitiesDB);
|
return _isInGame && SimModeUtil.IsBuildMode(entitiesDB);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsSimulationMode()
|
public bool IsSimulationMode()
|
||||||
{
|
{
|
||||||
return _isInGame && TimeRunningModeUtil.IsTimeRunningMode(entitiesDB);
|
return _isInGame && SimModeUtil.IsSimulationMode(entitiesDB);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -6,10 +6,10 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Engines
|
namespace GamecraftModdingAPI.Utility
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base engine interface used by all TechbloxModdingAPI engines
|
/// Base engine interface used by all GamecraftModdingAPI engines
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IApiEngine : IEngine, IQueryingEntitiesEngine, IDisposable
|
public interface IApiEngine : IEngine, IQueryingEntitiesEngine, IDisposable
|
||||||
{
|
{
|
||||||
|
@ -17,10 +17,5 @@ namespace TechbloxModdingAPI.Engines
|
||||||
/// The name of the engine
|
/// The name of the engine
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Name { get; }
|
string Name { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the emitter can be removed with Manager.RemoveEventEmitter(name)
|
|
||||||
/// </summary>
|
|
||||||
bool isRemovable { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,11 +6,11 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Utility
|
namespace GamecraftModdingAPI.Utility
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Utility class to access Techblox's built-in logging capabilities.
|
/// Utility class to access Gamecraft's built-in logging capabilities.
|
||||||
/// The log is saved to %APPDATA%\..\LocalLow\FreeJam\Techblox\Player.Log
|
/// The log is saved to %APPDATA%\..\LocalLow\FreeJam\Gamecraft\Player.Log
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class Logging
|
public static class Logging
|
||||||
{
|
{
|
||||||
|
@ -21,7 +21,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a regular message to Techblox's log
|
/// Write a regular message to Gamecraft's log
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">The object to log</param>
|
/// <param name="obj">The object to log</param>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
@ -37,7 +37,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a debug message to Techblox's log
|
/// Write a debug message to Gamecraft's log
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">The object to log</param>
|
/// <param name="obj">The object to log</param>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
@ -53,7 +53,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a debug message and object to Techblox's log
|
/// Write a debug message and object to Gamecraft's log
|
||||||
/// The reason this method exists in Svelto.Console is beyond my understanding
|
/// The reason this method exists in Svelto.Console is beyond my understanding
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the extra debug object</typeparam>
|
/// <typeparam name="T">The type of the extra debug object</typeparam>
|
||||||
|
@ -72,7 +72,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write an error message to Techblox's log
|
/// Write an error message to Gamecraft's log
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">The object to log</param>
|
/// <param name="obj">The object to log</param>
|
||||||
/// <param name="extraData">The extra data to pass to the ILogger</param>
|
/// <param name="extraData">The extra data to pass to the ILogger</param>
|
||||||
|
@ -83,7 +83,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write an exception to Techblox's log and to the screen and exit game
|
/// Write an exception to Gamecraft's log
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="e">The exception to log</param>
|
/// <param name="e">The exception to log</param>
|
||||||
/// <param name="extraData">The extra data to pass to the ILogger.
|
/// <param name="extraData">The extra data to pass to the ILogger.
|
||||||
|
@ -95,7 +95,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write an exception message to Techblox's log and to the screen and exit game
|
/// Write an exception message to Gamecraft's log
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">The object to log</param>
|
/// <param name="obj">The object to log</param>
|
||||||
/// <param name="e">The exception to log</param>
|
/// <param name="e">The exception to log</param>
|
||||||
|
@ -114,7 +114,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a warning message to Techblox's log
|
/// Write a warning message to Gamecraft's log
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">The object to log</param>
|
/// <param name="obj">The object to log</param>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
@ -123,10 +123,28 @@ namespace TechbloxModdingAPI.Utility
|
||||||
Svelto.Console.LogWarning(obj.ToString());
|
Svelto.Console.LogWarning(obj.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete("SystemLog was removed from Svelto.Common")]
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void SystemLog(string msg)
|
||||||
|
{
|
||||||
|
Svelto.Console.Log(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write a message to stdout (ie the terminal, like Command Prompt or PowerShell)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object to log</param>
|
||||||
|
[Obsolete("SystemLog was removed from Svelto.Common")]
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void SystemLog(object obj)
|
||||||
|
{
|
||||||
|
Svelto.Console.Log(obj.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
// descriptive logging
|
// descriptive logging
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a descriptive message to Techblox's log only when the API is a Debug build
|
/// Write a descriptive message to Gamecraft's log only when the API is a Debug build
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">The object to log</param>
|
/// <param name="obj">The object to log</param>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
@ -138,7 +156,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a descriptive message to Techblox's log including the current time and the calling method's name
|
/// Write a descriptive message to Gamecraft's log including the current time and the calling method's name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">The object to log</param>
|
/// <param name="obj">The object to log</param>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
@ -151,7 +169,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
// CLI logging
|
// CLI logging
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a message to Techblox's command line
|
/// Write a message to Gamecraft's command line
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">The object to log</param>
|
/// <param name="obj">The object to log</param>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
@ -163,11 +181,11 @@ namespace TechbloxModdingAPI.Utility
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void CommandLog(string msg)
|
public static void CommandLog(string msg)
|
||||||
{
|
{
|
||||||
Log(msg);
|
uREPL.Log.Output(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write an error message to Techblox's command line
|
/// Write an error message to Gamecraft's command line
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">The object to log</param>
|
/// <param name="obj">The object to log</param>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
@ -179,11 +197,11 @@ namespace TechbloxModdingAPI.Utility
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void CommandLogError(string msg)
|
public static void CommandLogError(string msg)
|
||||||
{
|
{
|
||||||
LogError(msg);
|
uREPL.Log.Error(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a warning message to Techblox's command line
|
/// Write a warning message to Gamecraft's command line
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">The object to log</param>
|
/// <param name="obj">The object to log</param>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
@ -195,7 +213,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void CommandLogWarning(string msg)
|
public static void CommandLogWarning(string msg)
|
||||||
{
|
{
|
||||||
LogWarning(msg);
|
uREPL.Log.Warn(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -5,9 +5,8 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using TechbloxModdingAPI.Engines;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Utility
|
namespace GamecraftModdingAPI.Utility
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Keeps track of custom menu-modifying engines
|
/// Keeps track of custom menu-modifying engines
|
||||||
|
@ -26,10 +25,6 @@ namespace TechbloxModdingAPI.Utility
|
||||||
{
|
{
|
||||||
Logging.MetaDebugLog($"Registering Menu IApiEngine {engine.Name}");
|
Logging.MetaDebugLog($"Registering Menu IApiEngine {engine.Name}");
|
||||||
_lastEngineRoot.AddEngine(engine);
|
_lastEngineRoot.AddEngine(engine);
|
||||||
if (engine is IFactoryEngine factoryEngine)
|
|
||||||
factoryEngine.Factory = _lastEngineRoot.GenerateEntityFactory();
|
|
||||||
if (engine is IFunEngine funEngine)
|
|
||||||
funEngine.Functions = _lastEngineRoot.GenerateEntityFunctions();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,23 +50,16 @@ namespace TechbloxModdingAPI.Utility
|
||||||
|
|
||||||
public static void RemoveMenuEngine(string name)
|
public static void RemoveMenuEngine(string name)
|
||||||
{
|
{
|
||||||
if (_menuEngines[name].isRemovable)
|
_menuEngines.Remove(name);
|
||||||
{
|
|
||||||
_menuEngines.Remove(name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RegisterEngines(EnginesRoot enginesRoot)
|
public static void RegisterEngines(EnginesRoot enginesRoot)
|
||||||
{
|
{
|
||||||
_lastEngineRoot = enginesRoot;
|
_lastEngineRoot = enginesRoot;
|
||||||
IEntityFactory factory = enginesRoot.GenerateEntityFactory();
|
|
||||||
IEntityFunctions functions = enginesRoot.GenerateEntityFunctions();
|
|
||||||
foreach (var key in _menuEngines.Keys)
|
foreach (var key in _menuEngines.Keys)
|
||||||
{
|
{
|
||||||
Logging.MetaDebugLog($"Registering Menu IApiEngine {_menuEngines[key].Name}");
|
Logging.MetaDebugLog($"Registering Menu IApiEngine {_menuEngines[key].Name}");
|
||||||
enginesRoot.AddEngine(_menuEngines[key]);
|
enginesRoot.AddEngine(_menuEngines[key]);
|
||||||
if (_menuEngines[key] is IFactoryEngine factEngine) factEngine.Factory = factory;
|
|
||||||
if(_menuEngines[key] is IFunEngine funEngine) funEngine.Functions = functions;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
28
GamecraftModdingAPI/Utility/MinimumSpecsCheckPatch.cs
Normal file
28
GamecraftModdingAPI/Utility/MinimumSpecsCheckPatch.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Harmony;
|
||||||
|
using RobocraftX.FrontEnd;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Utility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Patch of bool RobocraftX.FrontEnd.MinimumSpecsCheck.CheckRequirementsMet()
|
||||||
|
/// </summary>
|
||||||
|
[HarmonyPatch(typeof(MinimumSpecsCheck), "CheckRequirementsMet")]
|
||||||
|
class MinimumSpecsCheckPatch
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Ignore result of the requirement check?
|
||||||
|
/// </summary>
|
||||||
|
public static bool ForcePassMinimumSpecCheck = false;
|
||||||
|
|
||||||
|
public static void Postfix(ref bool __result)
|
||||||
|
{
|
||||||
|
__result = __result || ForcePassMinimumSpecCheck;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
GamecraftModdingAPI/Utility/SteamInitPatch.cs
Normal file
30
GamecraftModdingAPI/Utility/SteamInitPatch.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Harmony;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Utility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Patch of bool RobocraftX.Common.SteamManager.VerifyOrInit()
|
||||||
|
/// This does not let you run Gamecraft without Steam.
|
||||||
|
/// DO NOT USE!
|
||||||
|
/// </summary>
|
||||||
|
[HarmonyPatch(typeof(SteamManager), "VerifyOrInit")]
|
||||||
|
class SteamInitPatch
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Ignore the result of steam initialization?
|
||||||
|
/// </summary>
|
||||||
|
public static bool ForcePassSteamCheck = false;
|
||||||
|
|
||||||
|
public static void Postfix(ref bool __result)
|
||||||
|
{
|
||||||
|
__result = __result || ForcePassSteamCheck;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
110
GamecraftModdingAPI/Utility/VersionTracking.cs
Normal file
110
GamecraftModdingAPI/Utility/VersionTracking.cs
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Svelto.ECS.Serialization;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Persistence;
|
||||||
|
using GamecraftModdingAPI.Events;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Utility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Tracks the API version the current game was built for.
|
||||||
|
/// For compatibility reasons, this must be enabled before it will work.
|
||||||
|
/// </summary>
|
||||||
|
public static class VersionTracking
|
||||||
|
{
|
||||||
|
private static readonly VersionTrackingEngine versionEngine = new VersionTrackingEngine();
|
||||||
|
|
||||||
|
private static bool isEnabled = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the API version saved in the current game.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The version.</returns>
|
||||||
|
public static uint GetVersion()
|
||||||
|
{
|
||||||
|
if (!isEnabled) return 0u;
|
||||||
|
return versionEngine.GetGameVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enable API version tracking.
|
||||||
|
/// </summary>
|
||||||
|
public static void Enable()
|
||||||
|
{
|
||||||
|
EventManager.AddEventEmitter(versionEngine);
|
||||||
|
isEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disable API version tracking.
|
||||||
|
/// </summary>
|
||||||
|
public static void Disable()
|
||||||
|
{
|
||||||
|
EventManager.AddEventEmitter(versionEngine);
|
||||||
|
isEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
SerializerManager.AddSerializer<ModVersionDescriptor>(new SimpleEntitySerializer<ModVersionDescriptor>(
|
||||||
|
(_) => { return new EGID[1] { new EGID(0u, ApiExclusiveGroups.versionGroup) }; }
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class VersionTrackingEngine : IEventEmitterEngine
|
||||||
|
{
|
||||||
|
public string Name { get; } = "GamecraftModdingAPIVersionTrackingGameEngine";
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public int type => -1;
|
||||||
|
|
||||||
|
public bool isRemovable => false;
|
||||||
|
|
||||||
|
public IEntityFactory Factory { set; private get; }
|
||||||
|
|
||||||
|
public void Dispose() { }
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
EGID egid = new EGID(0u, ApiExclusiveGroups.versionGroup);
|
||||||
|
if (!entitiesDB.Exists<ModVersionStruct>(egid))
|
||||||
|
{
|
||||||
|
Version currentVersion = Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
|
int v = (currentVersion.Major * 1000) + (currentVersion.Minor);
|
||||||
|
Factory.BuildEntity<ModVersionDescriptor>(egid).Init<ModVersionStruct>(new ModVersionStruct
|
||||||
|
{
|
||||||
|
version = (uint)v
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint GetGameVersion()
|
||||||
|
{
|
||||||
|
return entitiesDB.QueryUniqueEntity<ModVersionStruct>(ApiExclusiveGroups.versionGroup).version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Emit() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ModVersionStruct : IEntityComponent
|
||||||
|
{
|
||||||
|
public uint version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ModVersionDescriptor: SerializableEntityDescriptor<ModVersionDescriptor._ModVersionDescriptor>
|
||||||
|
{
|
||||||
|
[HashName("GamecraftModdingAPIVersionV0")]
|
||||||
|
public class _ModVersionDescriptor : IEntityDescriptor
|
||||||
|
{
|
||||||
|
public IComponentBuilder[] componentsToBuild { get; } = new IComponentBuilder[]{
|
||||||
|
new SerializableComponentBuilder<SerializationType, ModVersionStruct>(((int)SerializationType.Network, new DefaultSerializer<ModVersionStruct>()), ((int)SerializationType.Storage, new DefaultSerializer<ModVersionStruct>())),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,25 +0,0 @@
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using Mono.Cecil;
|
|
||||||
|
|
||||||
Console.WriteLine("Starting assembly editing...");
|
|
||||||
var fileRegex =
|
|
||||||
new Regex(".*(Techblox|Gamecraft|RobocraftX|FullGame|RobocraftECS|DataLoader|RCX|GameState|Svelto\\.ECS)[^/]*(\\.dll)");
|
|
||||||
foreach (var file in Directory.EnumerateFiles(@"../../../../../ref/Techblox_Data/Managed"))
|
|
||||||
{
|
|
||||||
if (!fileRegex.IsMatch(file)) continue;
|
|
||||||
Console.WriteLine(file);
|
|
||||||
ProcessAssembly(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcessAssembly(string path)
|
|
||||||
{
|
|
||||||
using var mod = ModuleDefinition.ReadModule(path, new(ReadingMode.Immediate) { ReadWrite = true });
|
|
||||||
foreach (var typeDefinition in mod.Types)
|
|
||||||
{
|
|
||||||
typeDefinition.IsPublic = true;
|
|
||||||
foreach (var method in typeDefinition.Methods) method.IsPublic = true;
|
|
||||||
foreach (var field in typeDefinition.Fields) field.IsPublic = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
mod.Write();
|
|
||||||
}
|
|
25
README.md
25
README.md
|
@ -1,31 +1,24 @@
|
||||||
# TechbloxModdingAPI
|
# GamecraftModdingAPI
|
||||||
|
|
||||||
Unofficial Techblox modding API for interfacing Techblox from mods.
|
Unofficial Gamecraft modding API for interfacing Gamecraft from mods.
|
||||||
|
|
||||||
The TechbloxModdingAPI aims to simplify the mods in two ways:
|
The GamecraftModdingAPI aims to simplify the mods in two ways:
|
||||||
- *Ease-of-Use* The API provides convenient ways to do common tasks such as moving blocks and adding commands.
|
- *Ease-of-Use* The API provides convenient ways to do common tasks such as moving blocks and adding commands.
|
||||||
All of the Harmony patching is done for you, so you can focus on writing your mod instead of reading swathes of undocumented code.
|
All of the Harmony patching is done for you, so you can focus on writing your mod instead of reading swathes of undocumented code.
|
||||||
- *Stability* The API aims to be reliable and consistent between versions.
|
- *Stability* The API aims to be reliable and consistent between versions.
|
||||||
This means your code won't break when the TechbloxModdingAPI or Techblox updates.
|
This means your code won't break when the GamecraftModdingAPI or Gamecraft updates.
|
||||||
|
|
||||||
For more info, please check out the [official documentation](https://mod.exmods.org).
|
For more info, please check out the [official documentation](https://mod.exmods.org).
|
||||||
|
|
||||||
For more support, join the ExMods [Discord](https://discord.exmods.org).
|
For more support, join the ExMods [Discord](https://discord.gg/xjnFxQV).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
[Please follow the official mod installation guide](https://www.exmods.org/guides/install.html) or use GCMM.
|
[Please follow the official mod installation guide](https://www.exmods.org/guides/install.html)
|
||||||
|
|
||||||
## Development
|
|
||||||
To get started, create a symbolic link called `ref` in the root of the project, or one folder higher, linking to the Techblox install folder.
|
|
||||||
This will allow your IDE to resolve references to Techblox files for building and IDE tools.
|
|
||||||
|
|
||||||
TechbloxModdingAPI version numbers follow the [Semantic Versioning guidelines](https://semver.org/).
|
|
||||||
|
|
||||||
## External Libraries
|
## External Libraries
|
||||||
TechbloxModdingAPI includes [Harmony](https://github.com/pardeike/Harmony) to modify the behaviour of existing Techblox code.
|
GamecraftModdingAPI includes [Harmony](https://github.com/pardeike/Harmony) to modify the behaviour of existing Gamecraft code.
|
||||||
|
|
||||||
# Disclaimer
|
# Disclaimer
|
||||||
This API is an unofficial modification of Techblox software, and is not endorsed or supported by FreeJam or Techblox.
|
This API is an unofficial modification of Gamecraft software, and is not endorsed or supported by FreeJam or Gamecraft.
|
||||||
The TechbloxModdingAPI developer(s) claim no rights on the Techblox code referenced within this project.
|
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/TechbloxModdingAPI/src/branch/master/LICENSE).
|
|
||||||
|
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio Version 16
|
|
||||||
VisualStudioVersion = 16.0.29411.108
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TechbloxModdingAPI", "TechbloxModdingAPI\TechbloxModdingAPI.csproj", "{7FD5A7D8-4F3E-426A-B07D-7DC70442A4DF}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeGenerator", "CodeGenerator\CodeGenerator.csproj", "{0EBB6400-95A7-4A3D-B2ED-BF31E364CC10}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MakeEverythingPublicInGame", "MakeEverythingPublicInGame\MakeEverythingPublicInGame.csproj", "{391A3107-E5C6-4A04-9467-6D868AA9A8B4}"
|
|
||||||
EndProject
|
|
||||||
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
|
|
||||||
{0EBB6400-95A7-4A3D-B2ED-BF31E364CC10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{0EBB6400-95A7-4A3D-B2ED-BF31E364CC10}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{0EBB6400-95A7-4A3D-B2ED-BF31E364CC10}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{0EBB6400-95A7-4A3D-B2ED-BF31E364CC10}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{0EBB6400-95A7-4A3D-B2ED-BF31E364CC10}.Test|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{0EBB6400-95A7-4A3D-B2ED-BF31E364CC10}.Test|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{391A3107-E5C6-4A04-9467-6D868AA9A8B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{391A3107-E5C6-4A04-9467-6D868AA9A8B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{391A3107-E5C6-4A04-9467-6D868AA9A8B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{391A3107-E5C6-4A04-9467-6D868AA9A8B4}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{391A3107-E5C6-4A04-9467-6D868AA9A8B4}.Test|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{391A3107-E5C6-4A04-9467-6D868AA9A8B4}.Test|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {72FB94D0-6C50-475B-81E0-C94C7D7A2A17}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
|
@ -1,58 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using HarmonyLib;
|
|
||||||
using Svelto.Tasks;
|
|
||||||
using Techblox.Anticheat.Client;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.App
|
|
||||||
{
|
|
||||||
public static class AntiAntiCheatPatch
|
|
||||||
{
|
|
||||||
private delegate bool AntiAnticheatDelegate(ref object __result);
|
|
||||||
|
|
||||||
private delegate bool AntiAnticheatDelegateBool(ref bool __result);
|
|
||||||
|
|
||||||
private delegate bool AntiAnticheatDelegateTask(ref IEnumerator<TaskContract> __result);
|
|
||||||
|
|
||||||
public static void Init(Harmony harmony)
|
|
||||||
{
|
|
||||||
var type = AccessTools.TypeByName("Techblox.Services.Eos.Anticheat.Client.Services.AnticheatClientService");
|
|
||||||
harmony.Patch(type.GetConstructors()[0], new HarmonyMethod(((Func<bool>) AntiAntiCheat).Method));
|
|
||||||
harmony.Patch(AccessTools.Method(type, "Shutdown"), new HarmonyMethod(((Func<bool>) AntiAntiCheat).Method));
|
|
||||||
harmony.Patch(AccessTools.Method(type, "StartProtectedSession"), new HarmonyMethod(((AntiAnticheatDelegate) AntiAntiCheat).Method));
|
|
||||||
harmony.Patch(AccessTools.Method(type, "StopProtectedSession"), new HarmonyMethod(((AntiAnticheatDelegateBool) AntiAntiCheat).Method));
|
|
||||||
harmony.Patch(AccessTools.Method("Techblox.Services.Eos.Anticheat.Client.EosGetPendingMessagesToSendServiceRequest:Execute"), new HarmonyMethod(((AntiAnticheatDelegateTask)AntiAntiCheatTask).Method));
|
|
||||||
harmony.Patch(AccessTools.Method("Techblox.Anticheat.Client.Engines.ProcessEACViolationEngine:PollAnticheatStatus"), new HarmonyMethod(((AntiAnticheatDelegateTask)AntiAntiCheatTask).Method));
|
|
||||||
harmony.Patch(AccessTools.Method(typeof(AnticheatClientCompositionRoot), "ClientComposeTimeRunning"), new HarmonyMethod(((Func<bool>)AntiAntiCheat).Method));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool AntiAntiCheat() => false;
|
|
||||||
|
|
||||||
private static bool AntiAntiCheat(ref object __result)
|
|
||||||
{
|
|
||||||
var targetType =
|
|
||||||
AccessTools.TypeByName("Techblox.Services.Eos.Anticheat.Client.Services.StartProtectedSessionResult");
|
|
||||||
var target = Activator.CreateInstance(targetType);
|
|
||||||
targetType.GetField("Success").SetValue(target, true);
|
|
||||||
__result = target;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool AntiAntiCheat(ref bool __result)
|
|
||||||
{
|
|
||||||
__result = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool AntiAntiCheatTask(ref IEnumerator<TaskContract> __result)
|
|
||||||
{
|
|
||||||
IEnumerator<TaskContract> Func()
|
|
||||||
{
|
|
||||||
yield return Yield.It;
|
|
||||||
}
|
|
||||||
|
|
||||||
__result = Func();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using TechbloxModdingAPI.Tests;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.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
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.Serialization;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.App
|
|
||||||
{
|
|
||||||
public class AppException : TechbloxModdingAPIException
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,171 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
|
||||||
using HarmonyLib;
|
|
||||||
|
|
||||||
using RobocraftX.Services;
|
|
||||||
using UnityEngine;
|
|
||||||
using RobocraftX.Common;
|
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.App
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The Techblox application that is running this code right now.
|
|
||||||
/// </summary>
|
|
||||||
public class Client
|
|
||||||
{
|
|
||||||
public static Client Instance { get; } = new Client();
|
|
||||||
|
|
||||||
protected static Func<object> ErrorHandlerInstanceGetter;
|
|
||||||
|
|
||||||
protected static Action<object, Error> EnqueueError;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An event that fires whenever the main menu is loaded.
|
|
||||||
/// </summary>
|
|
||||||
public static event EventHandler<MenuEventArgs> EnterMenu
|
|
||||||
{
|
|
||||||
add => Game.menuEngine.EnterMenu += value;
|
|
||||||
remove => Game.menuEngine.EnterMenu -= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An event that fire whenever the main menu is exited.
|
|
||||||
/// </summary>
|
|
||||||
public static event EventHandler<MenuEventArgs> ExitMenu
|
|
||||||
{
|
|
||||||
add => Game.menuEngine.ExitMenu += value;
|
|
||||||
remove => Game.menuEngine.ExitMenu -= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Techblox 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 (!Game.menuEngine.IsInMenu) return Array.Empty<Game>();
|
|
||||||
return Game.menuEngine.GetMyGames();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether Techblox 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 => Game.menuEngine.IsInMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Open a popup which prompts the user to click a button.
|
|
||||||
/// This reuses Techblox'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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CloseCurrentPrompt()
|
|
||||||
{
|
|
||||||
object errorHandlerInstance = ErrorHandlerInstanceGetter();
|
|
||||||
var popup = GetPopupCloseMethods(errorHandlerInstance);
|
|
||||||
popup.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SelectFirstPromptButton()
|
|
||||||
{
|
|
||||||
object errorHandlerInstance = ErrorHandlerInstanceGetter();
|
|
||||||
var popup = GetPopupCloseMethods(errorHandlerInstance);
|
|
||||||
popup.FirstButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SelectSecondPromptButton()
|
|
||||||
{
|
|
||||||
object errorHandlerInstance = ErrorHandlerInstanceGetter();
|
|
||||||
var popup = GetPopupCloseMethods(errorHandlerInstance);
|
|
||||||
popup.SecondButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
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("TechbloxModdingAPI.App.Client:GenInstanceGetter")
|
|
||||||
.MakeGenericMethod(errorHandler)
|
|
||||||
.Invoke(null, new object[0]);
|
|
||||||
EnqueueError = (Action<object, Error>) AccessTools.Method("TechbloxModdingAPI.App.Client:GenEnqueueError")
|
|
||||||
.MakeGenericMethod(errorHandler, errorHandle)
|
|
||||||
.Invoke(null, new object[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 Close, Action FirstButton, Action SecondButton) _errorPopup;
|
|
||||||
|
|
||||||
private static (Action Close, Action FirstButton, Action SecondButton) GetPopupCloseMethods(object handler)
|
|
||||||
{
|
|
||||||
if (_errorPopup.Close != null)
|
|
||||||
return _errorPopup;
|
|
||||||
Type errorHandler = handler.GetType();
|
|
||||||
FieldInfo field = AccessTools.Field(errorHandler, "errorPopup");
|
|
||||||
var errorPopup = (ErrorPopup)field.GetValue(handler);
|
|
||||||
MethodInfo info = AccessTools.Method(errorPopup.GetType(), "ClosePopup");
|
|
||||||
var close = (Action)Delegate.CreateDelegate(typeof(Action), errorPopup, info);
|
|
||||||
info = AccessTools.Method(errorPopup.GetType(), "HandleFirstOption");
|
|
||||||
var first = (Action)Delegate.CreateDelegate(typeof(Action), errorPopup, info);
|
|
||||||
info = AccessTools.Method(errorPopup.GetType(), "HandleSecondOption");
|
|
||||||
var second = (Action)Delegate.CreateDelegate(typeof(Action), errorPopup, info);
|
|
||||||
_errorPopup = (close, first, second);
|
|
||||||
return _errorPopup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
using System;
|
|
||||||
using HarmonyLib;
|
|
||||||
|
|
||||||
using RobocraftX.Services;
|
|
||||||
|
|
||||||
using TechbloxModdingAPI.Tests;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.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.Instance.PromptUser(popup2);
|
|
||||||
}
|
|
||||||
|
|
||||||
[APITestCase(TestType.Menu)]
|
|
||||||
public static void TestPopUp1()
|
|
||||||
{
|
|
||||||
Client.Instance.PromptUser(popup1);
|
|
||||||
}
|
|
||||||
|
|
||||||
[APITestCase(TestType.Menu)]
|
|
||||||
public static void TestPopUpClose1()
|
|
||||||
{
|
|
||||||
Client.Instance.CloseCurrentPrompt();
|
|
||||||
}
|
|
||||||
|
|
||||||
[APITestCase(TestType.Menu)]
|
|
||||||
public static void TestPopUpClose2()
|
|
||||||
{
|
|
||||||
Client.Instance.CloseCurrentPrompt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.App
|
|
||||||
{
|
|
||||||
public enum CurrentGameMode
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
/// <summary>
|
|
||||||
/// Building a world
|
|
||||||
/// </summary>
|
|
||||||
Build,
|
|
||||||
/// <summary>
|
|
||||||
/// Playing on a map
|
|
||||||
/// </summary>
|
|
||||||
Play,
|
|
||||||
/// <summary>
|
|
||||||
/// Viewing a prefab (doesn't exist anymore)
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete]
|
|
||||||
View,
|
|
||||||
/// <summary>
|
|
||||||
/// Viewing a tutorial (doesn't exist anymore)
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete]
|
|
||||||
Tutorial
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,490 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
using RobocraftX.GUI.MyGamesScreen;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Techblox.GameSelection;
|
|
||||||
|
|
||||||
using TechbloxModdingAPI.Blocks;
|
|
||||||
using TechbloxModdingAPI.Tasks;
|
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.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 internal 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:TechbloxModdingAPI.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:TechbloxModdingAPI.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:TechbloxModdingAPI.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, Techblox 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 gameEngine.GetGameData().saveName;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (!VerifyMode()) return;
|
|
||||||
if (menuMode)
|
|
||||||
{
|
|
||||||
menuEngine.SetGameName(EGID, value);
|
|
||||||
} // Save details are directly saved from user input or not changed at all when in game
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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);
|
|
||||||
} // 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 gameEngine.GetGameData().gameID;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (!VerifyMode()) return;
|
|
||||||
if (menuMode)
|
|
||||||
{
|
|
||||||
menuEngine.GetGameInfo(EGID).SavedGamePath.Set(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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>
|
|
||||||
[Obsolete]
|
|
||||||
public ulong WorkshopId
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return 0uL; // Not supported anymore
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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>
|
|
||||||
/// The mode of the game.
|
|
||||||
/// </summary>
|
|
||||||
public CurrentGameMode Mode
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (menuMode || !VerifyMode()) return CurrentGameMode.None;
|
|
||||||
return gameEngine.GetGameData().gameMode == GameMode.CreateWorld ? CurrentGameMode.Build : CurrentGameMode.Play;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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.
|
|
||||||
/// The provided getter function is called each frame so make sure it returns quickly.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">Debug info identifier.</param>
|
|
||||||
/// <param name="contentGetter">A function that returns the current information.</param>
|
|
||||||
public 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("game_" + 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("game_" + id);
|
|
||||||
return debugIds.Remove(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Add information to the in-game debug display.
|
|
||||||
/// This debug info will be present for all games until it is manually removed.
|
|
||||||
/// The provided getter function is called each frame so make sure it returns quickly.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">Debug info identifier.</param>
|
|
||||||
/// <param name="contentGetter">A function that returns the current information.</param>
|
|
||||||
public static void AddPersistentDebugInfo(string id, Func<string> contentGetter)
|
|
||||||
{
|
|
||||||
debugOverlayEngine.SetInfo("persistent_" + id, contentGetter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove persistent information from the in-game debug display.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns><c>true</c>, if debug info was removed, <c>false</c> otherwise.</returns>
|
|
||||||
/// <param name="id">Debug info identifier.</param>
|
|
||||||
public static bool RemovePersistentDebugInfo(string id)
|
|
||||||
{
|
|
||||||
return debugOverlayEngine.RemoveInfo("persistent_" + id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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] = Block.New(blockEGIDs[b]);
|
|
||||||
}
|
|
||||||
return blocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Enable the screenshot taker for updating the game's screenshot. Breaks the pause menu in a new save.
|
|
||||||
/// </summary>
|
|
||||||
public void EnableScreenshotTaker()
|
|
||||||
{
|
|
||||||
if (!VerifyMode()) return;
|
|
||||||
gameEngine.EnableScreenshotTaker();
|
|
||||||
}
|
|
||||||
|
|
||||||
~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);
|
|
||||||
GameEngineManager.AddGameEngine(buildSimEventEngine);
|
|
||||||
MenuEngineManager.AddMenuEngine(menuEngine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using RobocraftX.Common;
|
|
||||||
using RobocraftX.StateSync;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Unity.Jobs;
|
|
||||||
using TechbloxModdingAPI.Engines;
|
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.App
|
|
||||||
{
|
|
||||||
public class GameBuildSimEventEngine : IApiEngine, IUnorderedInitializeOnTimeRunningModeEntered, IUnorderedInitializeOnTimeStoppedModeEntered
|
|
||||||
{
|
|
||||||
public WrappedHandler<GameEventArgs> SimulationMode;
|
|
||||||
|
|
||||||
public WrappedHandler<GameEventArgs> BuildMode;
|
|
||||||
|
|
||||||
public string Name => "TechbloxModdingAPIBuildSimEventGameEngine";
|
|
||||||
|
|
||||||
public bool isRemovable => false;
|
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { set; private get; }
|
|
||||||
|
|
||||||
public void Dispose() { }
|
|
||||||
|
|
||||||
public void Ready() { }
|
|
||||||
|
|
||||||
public JobHandle OnInitializeTimeRunningMode(JobHandle inputDeps)
|
|
||||||
{
|
|
||||||
SimulationMode.Invoke(this, new GameEventArgs { GameName = "", GamePath = "" }); // TODO
|
|
||||||
return inputDeps;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JobHandle OnInitializeTimeStoppedMode(JobHandle inputDeps)
|
|
||||||
{
|
|
||||||
BuildMode.Invoke(this, new GameEventArgs { GameName = "", GamePath = "" });
|
|
||||||
return inputDeps;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct GameEventArgs
|
|
||||||
{
|
|
||||||
public string GameName;
|
|
||||||
|
|
||||||
public string GamePath;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,195 +0,0 @@
|
||||||
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 RobocraftX.Blocks;
|
|
||||||
using RobocraftX.Common.Loading;
|
|
||||||
using RobocraftX.Multiplayer;
|
|
||||||
using RobocraftX.ScreenshotTaker;
|
|
||||||
using Techblox.Environment.Transition;
|
|
||||||
using Techblox.GameSelection;
|
|
||||||
|
|
||||||
using TechbloxModdingAPI.Blocks;
|
|
||||||
using TechbloxModdingAPI.Engines;
|
|
||||||
using TechbloxModdingAPI.Input;
|
|
||||||
using TechbloxModdingAPI.Players;
|
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.App
|
|
||||||
{
|
|
||||||
public class GameGameEngine : IApiEngine, IReactOnAddAndRemove<LoadingActionEntityStruct>
|
|
||||||
{
|
|
||||||
public WrappedHandler<GameEventArgs> EnterGame;
|
|
||||||
|
|
||||||
public WrappedHandler<GameEventArgs> ExitGame;
|
|
||||||
|
|
||||||
public string Name => "TechbloxModdingAPIGameInfoMenuEngine";
|
|
||||||
|
|
||||||
public bool isRemovable => false;
|
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { set; private get; }
|
|
||||||
|
|
||||||
private bool enteredGame;
|
|
||||||
private bool loadingFinished;
|
|
||||||
private bool playerJoined;
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (GameReloadedPatch.IsReload)
|
|
||||||
return; // Toggling time mode
|
|
||||||
ExitGame.Invoke(this, new GameEventArgs { GameName = GetGameData().saveName, GamePath = GetGameData().gameID });
|
|
||||||
IsInGame = false;
|
|
||||||
loadingFinished = false;
|
|
||||||
playerJoined = false;
|
|
||||||
enteredGame = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Ready()
|
|
||||||
{
|
|
||||||
if (GameReloadedPatch.IsReload)
|
|
||||||
return; // Toggling time mode
|
|
||||||
enteredGame = true;
|
|
||||||
Player.Joined += OnPlayerJoined;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPlayerJoined(object sender, PlayerEventArgs args)
|
|
||||||
{
|
|
||||||
if (args.Player.Type != PlayerType.Local) return;
|
|
||||||
playerJoined = true;
|
|
||||||
Player.Joined -= OnPlayerJoined;
|
|
||||||
CheckJoinEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
// game functionality
|
|
||||||
|
|
||||||
public bool IsInGame
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
} = false;
|
|
||||||
|
|
||||||
public void ExitCurrentGame(bool async = false)
|
|
||||||
{
|
|
||||||
if (async)
|
|
||||||
{
|
|
||||||
ExitCurrentGameAsync().RunOn(ClientLean.EveryFrameStepRunner_TimeRunningAndStopped);
|
|
||||||
}
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
if (TimeRunningModeUtil.IsTimeStoppedMode(entitiesDB))
|
|
||||||
FakeInput.ActionInput(toggleMode: true);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IEnumerator<TaskContract> ReloadBuildModeTask()
|
|
||||||
{
|
|
||||||
SwitchAnimationUtil.Start(entitiesDB);
|
|
||||||
while (SwitchAnimationUtil.IsFadeOutActive(entitiesDB))
|
|
||||||
yield return (TaskContract)Yield.It;
|
|
||||||
FullGameFields._multiplayerParams.MultiplayerMode = MultiplayerMode.SinglePlayer;
|
|
||||||
AccessTools.Method(typeof(FullGameCompositionRoot), "ReloadGame")
|
|
||||||
.Invoke(FullGameFields.Instance, new object[] { });
|
|
||||||
}
|
|
||||||
|
|
||||||
ReloadBuildModeTask().RunOn(ClientLean.UIScheduler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public EGID[] GetAllBlocksInGame(BlockIDs filter = BlockIDs.Invalid)
|
|
||||||
{
|
|
||||||
var allBlocks = entitiesDB.QueryEntities<BlockTagEntityStruct>();
|
|
||||||
List<EGID> blockEGIDs = new List<EGID>();
|
|
||||||
foreach (var ((_, ids, count), group) in allBlocks)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
var id = new EGID(ids[i], group);
|
|
||||||
uint dbid;
|
|
||||||
if (filter == BlockIDs.Invalid)
|
|
||||||
dbid = (uint)filter;
|
|
||||||
else
|
|
||||||
dbid = entitiesDB.QueryEntity<DBEntityStruct>(id).DBID;
|
|
||||||
var ownership = entitiesDB.QueryEntity<BlockOwnershipComponent>(id).BlockOwnership;
|
|
||||||
if ((ownership & BlockOwnership.User) != 0 && dbid == (ulong)filter)
|
|
||||||
blockEGIDs.Add(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return blockEGIDs.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void EnableScreenshotTaker()
|
|
||||||
{
|
|
||||||
ref var local = ref entitiesDB.QueryEntity<ScreenshotModeEntityStruct>(ScreenshotTakerEgids.ScreenshotTaker);
|
|
||||||
if (local.enabled)
|
|
||||||
return;
|
|
||||||
local.enabled = true;
|
|
||||||
entitiesDB.PublishEntityChange<ScreenshotModeEntityStruct>(ScreenshotTakerEgids.ScreenshotTaker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameSelectionComponent GetGameData()
|
|
||||||
{
|
|
||||||
return entitiesDB.QueryEntity<GameSelectionComponent>(GameSelectionConstants.GameSelectionEGID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(ref LoadingActionEntityStruct entityComponent, EGID egid)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Remove(ref LoadingActionEntityStruct entityComponent, EGID egid)
|
|
||||||
{ // Finished loading
|
|
||||||
if (!enteredGame) return;
|
|
||||||
enteredGame = false;
|
|
||||||
loadingFinished = true;
|
|
||||||
CheckJoinEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CheckJoinEvent()
|
|
||||||
{
|
|
||||||
if (!loadingFinished || !playerJoined) return;
|
|
||||||
EnterGame.Invoke(this, new GameEventArgs { GameName = GetGameData().saveName, GamePath = GetGameData().gameID });
|
|
||||||
IsInGame = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,197 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
|
||||||
using HarmonyLib;
|
|
||||||
|
|
||||||
using RobocraftX;
|
|
||||||
using RobocraftX.GUI;
|
|
||||||
using RobocraftX.GUI.MyGamesScreen;
|
|
||||||
using RobocraftX.Multiplayer;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Svelto.ECS.Experimental;
|
|
||||||
using Techblox.GameSelection;
|
|
||||||
|
|
||||||
using TechbloxModdingAPI.Engines;
|
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.App
|
|
||||||
{
|
|
||||||
public class GameMenuEngine : IFactoryEngine
|
|
||||||
{
|
|
||||||
public WrappedHandler<MenuEventArgs> EnterMenu;
|
|
||||||
|
|
||||||
public WrappedHandler<MenuEventArgs> ExitMenu;
|
|
||||||
public IEntityFactory Factory { set; private get; }
|
|
||||||
|
|
||||||
public string Name => "TechbloxModdingAPIGameInfoGameEngine";
|
|
||||||
|
|
||||||
public bool isRemovable => false;
|
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { set; private get; }
|
|
||||||
|
|
||||||
public GameMenuEngine()
|
|
||||||
{
|
|
||||||
MenuEnteredEnginePatch.EnteredExitedMenu = () =>
|
|
||||||
{
|
|
||||||
if (IsInMenu)
|
|
||||||
EnterMenu.Invoke(this, new MenuEventArgs { });
|
|
||||||
else
|
|
||||||
ExitMenu.Invoke(this, new MenuEventArgs { });
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Ready()
|
|
||||||
{
|
|
||||||
MenuEnteredEnginePatch.IsInMenu = true; // At first it uses ActivateMenu(), then GoToMenu() which is patched
|
|
||||||
MenuEnteredEnginePatch.EnteredExitedMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
// game functionality
|
|
||||||
|
|
||||||
public bool IsInMenu => MenuEnteredEnginePatch.IsInMenu;
|
|
||||||
|
|
||||||
public Game[] GetMyGames()
|
|
||||||
{
|
|
||||||
var (mgsevs, count) = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames);
|
|
||||||
Game[] games = new Game[count];
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
Utility.Logging.MetaDebugLog($"Found game named {mgsevs[i].GameName}");
|
|
||||||
games[i] = new Game(mgsevs[i].ID);
|
|
||||||
}
|
|
||||||
return games;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CreateMyGame(EGID id, string path = "", uint thumbnailId = 0, string gameName = "", string creatorName = "", string description = "", long createdDate = 0L)
|
|
||||||
{
|
|
||||||
EntityInitializer 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()
|
|
||||||
{
|
|
||||||
var (games, count) = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames);
|
|
||||||
uint max = 0;
|
|
||||||
for (int i = 0; i < 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.FileId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool EnterGame(ECSString gameName, string fileId, bool autoEnterSim = false)
|
|
||||||
{
|
|
||||||
FullGameFields._multiplayerParams.MultiplayerMode = MultiplayerMode.SinglePlayer;
|
|
||||||
ref var selection = ref entitiesDB.QueryEntity<GameSelectionComponent>(GameSelectionConstants.GameSelectionEGID);
|
|
||||||
selection.userContentID.Set(fileId);
|
|
||||||
selection.triggerStart = true;
|
|
||||||
selection.saveType = SaveType.ExistingSave;
|
|
||||||
selection.saveName = gameName;
|
|
||||||
selection.gameMode = GameMode.PlayGame;
|
|
||||||
selection.gameID.Set("GAMEID_Road_Track"); //TODO: Expose to the API
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 dynamic GetGameViewInfo(EGID id)
|
|
||||||
{
|
|
||||||
dynamic structOptional = AccessTools.Method("TechbloxModdingAPI.Utility.NativeApiExtensions:QueryEntityOptional", new []{typeof(EntitiesDB), typeof(EGID)})
|
|
||||||
.MakeGenericMethod(AccessTools.TypeByName("RobocraftX.GUI.MyGamesScreen.MyGamesSlotEntityViewStruct"))
|
|
||||||
.Invoke(null, new object[] {entitiesDB, new EGID(id.entityID, MyGamesScreenExclusiveGroups.GameSlotGuiEntities)});
|
|
||||||
if (structOptional == null) throw new Exception("Could not get game slot entity");
|
|
||||||
return structOptional ? structOptional : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref T GetComponent<T>(EGID id) where T: unmanaged, IEntityComponent
|
|
||||||
{
|
|
||||||
return ref entitiesDB.QueryEntity<T>(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class MyGameDataEntityDescriptor_DamnItFJWhyDidYouMakeThisInternal : GenericEntityDescriptor<MyGameDataEntityStruct> { }
|
|
||||||
|
|
||||||
[HarmonyPatch]
|
|
||||||
static class MenuEnteredEnginePatch
|
|
||||||
{
|
|
||||||
internal static bool IsInMenu;
|
|
||||||
internal static Action EnteredExitedMenu;
|
|
||||||
public static void Postfix()
|
|
||||||
{
|
|
||||||
IsInMenu = true;
|
|
||||||
EnteredExitedMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MethodBase TargetMethod()
|
|
||||||
{
|
|
||||||
return AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToMenu");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch]
|
|
||||||
static class MenuExitedEnginePatch
|
|
||||||
{
|
|
||||||
public static void Prefix()
|
|
||||||
{
|
|
||||||
MenuEnteredEnginePatch.IsInMenu = false;
|
|
||||||
MenuEnteredEnginePatch.EnteredExitedMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MethodBase TargetMethod()
|
|
||||||
{
|
|
||||||
return AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToGame");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct MenuEventArgs
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue