Compare commits
229 commits
Author | SHA1 | Date | |
---|---|---|---|
5dff88d703 | |||
a8a451f8e4 | |||
67f32b8810 | |||
b3b1e9b9e7 | |||
e0cd7f6aec | |||
23439abde3 | |||
5e90c5ee26 | |||
5117b69500 | |||
f70b65e796 | |||
55344d1352 | |||
dfe1bfb504 | |||
a610623644 | |||
f9aa6ce2bb | |||
23abe47c72 | |||
c0ef8f1fae | |||
c4a9125ed3 | |||
3eecdf2cf5 | |||
2db7b607f0 | |||
7f63944a6e | |||
c6dae688fe | |||
7b2ac973d8 | |||
0ec47cd38b | |||
ddaa933e7d | |||
5fea7dc3b3 | |||
4684b33c69 | |||
d27bcee8d5 | |||
09d3c5e81c | |||
966fdd4c3a | |||
5602ef9268 | |||
93a0b2287a | |||
4ac8d53a2d | |||
f817becc6e | |||
2a1782cd82 | |||
5c1fe34f46 | |||
ef1b3de1a1 | |||
fef66c349d | |||
e3a7961be4 | |||
f53d0b63e7 | |||
619a5003cf | |||
6204b226d1 | |||
4bd636b8ed | |||
8a03277d84 | |||
aa947eaba1 | |||
63295f82c9 | |||
033ebdb86d | |||
2513040343 | |||
77d5e59ef6 | |||
9693341d7a | |||
c0eae77421 | |||
3351993936 | |||
49c3b60963 | |||
ece71c45a6 | |||
2a1676ce0f | |||
74d5a5c6b1 | |||
76faa69c74 | |||
52ccbe4dad | |||
0b2ffef0d3 | |||
99f077a917 | |||
c1c226ef2a | |||
|
06cb911ea3 | ||
b31eaa20c0 | |||
94c0c1370b | |||
b8fd14d934 | |||
5bfd0b7f10 | |||
220eb02a19 | |||
e8515ef42b | |||
f5e3010e48 | |||
1cbe252727 | |||
b3f7dcd36d | |||
e9df67f462 | |||
70b322583a | |||
4f0645492c | |||
58d703f502 | |||
|
db08bf1ac0 | ||
dd2680abd5 | |||
4807c12387 | |||
3432a1ae33 | |||
7a53e1d32f | |||
aa12b848d0 | |||
b6b9a29a3c | |||
6fedf90380 | |||
3eef859095 | |||
858a5c9b5c | |||
d238c97906 | |||
61184145a9 | |||
2d99d1d478 | |||
78ee3b3bcd | |||
aea3ef3623 | |||
62afd3b780 | |||
5172b13b7c | |||
c914b5b393 | |||
a6f52070ee | |||
807470e289 | |||
df6a2e84e1 | |||
6e03847ab0 | |||
55b38f1678 | |||
eb7a09ed22 | |||
6a2459b3e7 | |||
cc4850a073 | |||
677c8b0907 | |||
1f688195af | |||
9a4ff858f3 | |||
124ef410c7 | |||
98e00de642 | |||
2d41026a05 | |||
a6b69d94c9 | |||
|
37e3c6f718 | ||
|
0ef875b6b2 | ||
d954060a5a | |||
fdc47832f4 | |||
|
95574a50f8 | ||
|
1c014e36ac | ||
879901f4b9 | |||
6a90739197 | |||
9c5c980c0b | |||
712ece86db | |||
a7f6a16231 | |||
4e16f251ee | |||
78f0ea0162 | |||
5dfb01ef0b | |||
432d6bcf96 | |||
|
be7d8ba33a | ||
56a64daa18 | |||
ab1ae51ece | |||
|
404c47c7c0 | ||
fad3b5cbf4 | |||
1f911b1d32 | |||
f30dcd251f | |||
680721256c | |||
64b42830a3 | |||
d744aaab79 | |||
3dd61b5e4f | |||
1c4e2a0db2 | |||
4f8feaa24b | |||
|
8eec1358e9 | ||
|
08138e3589 | ||
987fbe673a | |||
4580ae3b66 | |||
f1376f5df6 | |||
2179ba6386 | |||
1a986056a1 | |||
|
d891f12701 | ||
|
1cb663b4d1 | ||
0bd348bd47 | |||
3929144171 | |||
|
c6a1ea35cc | ||
b0b496f22f | |||
4701b3577d | |||
abbb83da26 | |||
64aace3bde | |||
9e9f56881f | |||
c9e71d84b4 | |||
|
4dfa7b0f4e | ||
1a0c98dd67 | |||
f2ce037564 | |||
92965404ce | |||
58cfba443e | |||
ee6a0e3af6 | |||
|
9e6edc19bd | ||
d581ec598a | |||
1e9d1c8f81 | |||
53bdd27166 | |||
c06ed340a2 | |||
f295f712b6 | |||
|
aae2057972 | ||
|
daf4a24bc9 | ||
|
11b94e384e | ||
cfdc5e8c26 | |||
|
fd97194903 | ||
2172364d26 | |||
|
89f354b647 | ||
|
50ebf4f0a6 | ||
|
167ea5388b | ||
|
8354123169 | ||
|
7f5a36cb62 | ||
|
e56871f5ef | ||
|
708dbdd81d | ||
|
ca0e6e089d | ||
|
b81562ea58 | ||
057a030c20 | |||
15485481a2 | |||
b53dff5d12 | |||
5264d98ce7 | |||
5e335e78ff | |||
7336fe8353 | |||
89d32956d9 | |||
|
ea8a9184bc | ||
|
926d968eed | ||
|
421faf7167 | ||
47126d2d79 | |||
c5e9599c46 | |||
3f2139d592 | |||
|
9e47bbcd9a | ||
|
cda57afade | ||
|
4a9ceecc29 | ||
16521ab7eb | |||
cc4ed3e174 | |||
|
e0aa052305 | ||
d842df7681 | |||
3592c6f464 | |||
5bbb54c0c5 | |||
aa0aefd41b | |||
f403feb298 | |||
|
6f589f1744 | ||
|
b376133d28 | ||
|
60f231f939 | ||
|
b6a5074fd2 | ||
|
189c3ca2a5 | ||
|
0019b7c073 | ||
|
78122ee445 | ||
|
c912f3ba64 | ||
9b1e2548d1 | |||
|
0d17a1b509 | ||
|
960ab16f0b | ||
|
d2c9cde1d2 | ||
ae1f53e119 | |||
62318b0843 | |||
3dcce18ceb | |||
448cf3af48 | |||
cae626197f | |||
|
cd78fd6718 | ||
f62211309e | |||
|
197fc5f2f9 | ||
|
6a137472c1 | ||
5660bfc28d | |||
dba7c0a46f | |||
|
98c7e624f8 | ||
|
2d89b82759 | ||
0b8491cecf |
194 changed files with 15805 additions and 6240 deletions
67
Automation/bump_version.py
Executable file
67
Automation/bump_version.py
Executable file
|
@ -0,0 +1,67 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
# this assumes a mostly semver-complient version number
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description="Increment 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)
|
27
Automation/gen_csproj.py
Normal file → Executable file
27
Automation/gen_csproj.py
Normal file → Executable file
|
@ -3,15 +3,24 @@
|
||||||
import argparse
|
import argparse
|
||||||
from pathlib import Path, PurePath
|
from pathlib import Path, PurePath
|
||||||
import re
|
import re
|
||||||
|
import os
|
||||||
|
|
||||||
DLL_EXCLUSIONS_REGEX = r"(System|Microsoft|Mono|IronPython|DiscordRPC)\."
|
DLL_EXCLUSIONS_REGEX = r"(System|Microsoft|Mono|IronPython|DiscordRPC|IllusionInjector|IllusionPlugin|netstandard)\."
|
||||||
|
|
||||||
def getAssemblyReferences(path):
|
def getAssemblyReferences(path):
|
||||||
asmDir = Path(path)
|
asmDir = Path(path)
|
||||||
result = list()
|
result = list()
|
||||||
|
addedPath = ""
|
||||||
|
if not asmDir.exists():
|
||||||
|
addedPath = "../"
|
||||||
|
asmDir = Path(addedPath + path)
|
||||||
for child in asmDir.iterdir():
|
for child in asmDir.iterdir():
|
||||||
if child.is_file() and re.search(DLL_EXCLUSIONS_REGEX, str(child), re.I) is None and str(child).lower().endswith(".dll"):
|
if child.is_file() and re.search(DLL_EXCLUSIONS_REGEX, str(child)) is None and str(child).lower().endswith(".dll"):
|
||||||
result.append(str(child).replace("\\", "/"))
|
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
|
return result
|
||||||
|
|
||||||
def buildReferencesXml(path):
|
def buildReferencesXml(path):
|
||||||
|
@ -27,16 +36,16 @@ def buildReferencesXml(path):
|
||||||
return "<!--Start Dependencies-->\n <ItemGroup>\n" + "".join(result) + " </ItemGroup>\n<!--End Dependencies-->"
|
return "<!--Start Dependencies-->\n <ItemGroup>\n" + "".join(result) + " </ItemGroup>\n<!--End Dependencies-->"
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(description="Generate GamecraftModdingAPI.csproj")
|
parser = argparse.ArgumentParser(description="Generate TechbloxModdingAPI.csproj")
|
||||||
# TODO (maybe?): add params for custom csproj read and write locations
|
# TODO (maybe?): add params for custom csproj read and write locations
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
print("Building Assembly references")
|
print("Building Assembly references")
|
||||||
asmXml = buildReferencesXml("../ref/Gamecraft_Data/Managed")
|
asmXml = buildReferencesXml("../ref_TB/Techblox_Data/Managed")
|
||||||
# print(asmXml)
|
# print(asmXml)
|
||||||
|
|
||||||
with open("../GamecraftModdingAPI/GamecraftModdingAPI.csproj", "r") as xmlFile:
|
with open("../TechbloxModdingAPI/TechbloxModdingAPI.csproj", "r") as xmlFile:
|
||||||
print("Parsing GamecraftModdingAPI.csproj")
|
print("Parsing TechbloxModdingAPI.csproj")
|
||||||
fileStr = xmlFile.read()
|
fileStr = xmlFile.read()
|
||||||
# print(fileStr)
|
# print(fileStr)
|
||||||
depsStart = re.search(r"\<!--\s*Start\s+Dependencies\s*--\>", fileStr)
|
depsStart = re.search(r"\<!--\s*Start\s+Dependencies\s*--\>", fileStr)
|
||||||
|
@ -44,8 +53,8 @@ if __name__ == "__main__":
|
||||||
if depsStart is None or depsEnd is None:
|
if depsStart is None or depsEnd is None:
|
||||||
print("Unable to find dependency XML comments, aborting!")
|
print("Unable to find dependency XML comments, aborting!")
|
||||||
exit(1)
|
exit(1)
|
||||||
newFileStr = fileStr[:depsStart.start()] + "\n" + asmXml + "\n" + fileStr[depsEnd.end() + 1:]
|
newFileStr = fileStr[:depsStart.start() - 1] + "\n" + asmXml + "\n" + fileStr[depsEnd.end() + 1:]
|
||||||
with open("../GamecraftModdingAPI/GamecraftModdingAPI.csproj", "w") as xmlFile:
|
with open("../TechbloxModdingAPI/TechbloxModdingAPI.csproj", "w") as xmlFile:
|
||||||
print("Writing Assembly references")
|
print("Writing Assembly references")
|
||||||
xmlFile.write(newFileStr)
|
xmlFile.write(newFileStr)
|
||||||
# print(newFileStr)
|
# print(newFileStr)
|
||||||
|
|
10
CodeGenerator/App.config
Normal file
10
CodeGenerator/App.config
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?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>
|
158
CodeGenerator/BlockClassGenerator.cs
Normal file
158
CodeGenerator/BlockClassGenerator.cs
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
1592
CodeGenerator/CodeGenerator.csproj
Normal file
1592
CodeGenerator/CodeGenerator.csproj
Normal file
File diff suppressed because it is too large
Load diff
53
CodeGenerator/Program.cs
Normal file
53
CodeGenerator/Program.cs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
CodeGenerator/packages.config
Normal file
4
CodeGenerator/packages.config
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Lib.Harmony" version="2.2.0" targetFramework="net472" />
|
||||||
|
</packages>
|
|
@ -1,25 +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}") = "GamecraftModdingAPI", "GamecraftModdingAPI\GamecraftModdingAPI.csproj", "{7FD5A7D8-4F3E-426A-B07D-7DC70442A4DF}"
|
|
||||||
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
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {72FB94D0-6C50-475B-81E0-C94C7D7A2A17}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
|
@ -1,319 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Svelto.ECS.EntityStructs;
|
|
||||||
using RobocraftX.Common;
|
|
||||||
using RobocraftX.Blocks;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
using Gamecraft.Blocks.GUI;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Blocks;
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A single (perhaps scaled) block. Properties may return default values if the block is removed and then setting them is ignored.
|
|
||||||
/// For specific block type operations, use the specialised block classes in the GamecraftModdingAPI.Blocks namespace.
|
|
||||||
/// </summary>
|
|
||||||
public class Block
|
|
||||||
{
|
|
||||||
protected static readonly PlacementEngine PlacementEngine = new PlacementEngine();
|
|
||||||
protected static readonly MovementEngine MovementEngine = new MovementEngine();
|
|
||||||
protected static readonly RotationEngine RotationEngine = new RotationEngine();
|
|
||||||
protected static readonly RemovalEngine RemovalEngine = new RemovalEngine();
|
|
||||||
protected static readonly SignalEngine SignalEngine = new SignalEngine();
|
|
||||||
|
|
||||||
protected internal static readonly BlockEngine BlockEngine = new BlockEngine();
|
|
||||||
|
|
||||||
/// <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="player">The player who placed the block</param>
|
|
||||||
/// <returns>The placed block or null if failed</returns>
|
|
||||||
public static Block PlaceNew(BlockIDs block, float3 position,
|
|
||||||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0,
|
|
||||||
int uscale = 1, float3 scale = default, Player player = null)
|
|
||||||
{
|
|
||||||
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
|
|
||||||
{
|
|
||||||
return new Block(PlacementEngine.PlaceBlock(block, color, darkness,
|
|
||||||
position, uscale, scale, player, rotation));
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Place a new block at the given position. If scaled, position means the center of the block. The default block size is 0.2 in terms of position.
|
|
||||||
/// Place blocks next to each other to connect them.
|
|
||||||
/// The placed block will be a complete block with a placement grid and collision which will be saved along with the game.
|
|
||||||
/// <para></para>
|
|
||||||
/// <para>This method waits for the block to be constructed in the game.</para>
|
|
||||||
/// </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="player">The player who placed the block</param>
|
|
||||||
/// <returns>The placed block or null if failed</returns>
|
|
||||||
public static async Task<Block> PlaceNewAsync(BlockIDs block, float3 position,
|
|
||||||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0,
|
|
||||||
int uscale = 1, float3 scale = default, Player player = null)
|
|
||||||
{
|
|
||||||
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var ret = new Block(PlacementEngine.PlaceBlock(block, color, darkness,
|
|
||||||
position, uscale, scale, player, rotation));
|
|
||||||
await AsyncUtils.WaitForSubmission();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logging.MetaDebugLog(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the most recently placed block.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The block object</returns>
|
|
||||||
public static Block GetLastPlacedBlock()
|
|
||||||
{
|
|
||||||
return new Block(BlockIdentifiers.LatestBlockID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Block(EGID id)
|
|
||||||
{
|
|
||||||
Id = id;
|
|
||||||
if (!BlockEngine.BlockExists(Id))
|
|
||||||
{
|
|
||||||
Sync();
|
|
||||||
if (!BlockEngine.BlockExists(Id))
|
|
||||||
{
|
|
||||||
throw new BlockDoesNotExistException($"Block {Id.entityID} must be placed using PlaceNew(...) since it does not exist yet");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Block(uint id) : this(new EGID(id, CommonExclusiveGroups.OWNED_BLOCKS_GROUP))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Synchronize newly created entity components with entities DB.
|
|
||||||
/// This forces a partial game tick, so it may be slow.
|
|
||||||
/// This also has the potential to make Gamecraft unstable.
|
|
||||||
/// Use this sparingly.
|
|
||||||
/// </summary>
|
|
||||||
protected static void Sync()
|
|
||||||
{
|
|
||||||
DeterministicStepCompositionRootPatch.SubmitEntitiesNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
public EGID Id { get; protected set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The block's current position or zero if the block no longer exists.
|
|
||||||
/// A block is 0.2 wide by default in terms of position.
|
|
||||||
/// </summary>
|
|
||||||
public float3 Position
|
|
||||||
{
|
|
||||||
get => Exists ? MovementEngine.GetPosition(Id.entityID) : float3.zero;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (Exists) MovementEngine.MoveBlock(Id.entityID, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The block's current rotation in degrees or zero if the block doesn't exist.
|
|
||||||
/// </summary>
|
|
||||||
public float3 Rotation
|
|
||||||
{
|
|
||||||
get => Exists ? RotationEngine.GetRotation(Id.entityID) : float3.zero;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (Exists) RotationEngine.RotateBlock(Id.entityID, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The block's non-uniform scale or zero if the block's invalid. Independent of the uniform scaling.
|
|
||||||
/// </summary>
|
|
||||||
public float3 Scale
|
|
||||||
{
|
|
||||||
get => BlockEngine.GetBlockInfo<ScalingEntityStruct>(Id).scale;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
BlockEngine.GetBlockInfo<ScalingEntityStruct>(Id).scale = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The block's uniform scale or zero if the block's invalid. Also sets the non-uniform scale.
|
|
||||||
/// </summary>
|
|
||||||
public int UniformScale
|
|
||||||
{
|
|
||||||
get => BlockEngine.GetBlockInfo<UniformBlockScaleEntityStruct>(Id).scaleFactor;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref var scaleStruct = ref BlockEngine.GetBlockInfo<UniformBlockScaleEntityStruct>(Id);
|
|
||||||
scaleStruct.scaleFactor = value;
|
|
||||||
Scale = new float3(value, value, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The block's type (ID). Returns BlockIDs.Invalid if the block doesn't exist anymore.
|
|
||||||
/// </summary>
|
|
||||||
public BlockIDs Type
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var id = (BlockIDs) BlockEngine.GetBlockInfo<DBEntityStruct>(Id, out var exists).DBID;
|
|
||||||
return exists ? id : BlockIDs.Invalid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The block's color. Returns BlockColors.Default if the block no longer exists.
|
|
||||||
/// </summary>
|
|
||||||
public BlockColor Color
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
byte index = BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(Id, out var exists).indexInPalette;
|
|
||||||
if (!exists) index = byte.MaxValue;
|
|
||||||
if (index == byte.MaxValue) return new BlockColor { Color = BlockColors.Default };
|
|
||||||
return new BlockColor { Color = (BlockColors)(index % 10), Darkness = (byte)(index / 10) };
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref var color = ref BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(Id);
|
|
||||||
color.indexInPalette = (byte)(value.Color + value.Darkness * 10);
|
|
||||||
color.overridePaletteColour = false;
|
|
||||||
color.needsUpdate = true;
|
|
||||||
BlockEngine.SetBlockColorFromPalette(ref color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The block's exact color. Gets reset to the palette color (Color property) after reentering the game.
|
|
||||||
/// </summary>
|
|
||||||
public float4 CustomColor
|
|
||||||
{
|
|
||||||
get => BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(Id).overriddenColour;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref var color = ref BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(Id);
|
|
||||||
color.overriddenColour = value;
|
|
||||||
color.overridePaletteColour = true;
|
|
||||||
color.needsUpdate = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The short text displayed on the block if applicable, or null.
|
|
||||||
/// Setting it is temporary to the session, it won't be saved.
|
|
||||||
/// </summary>
|
|
||||||
public string Label
|
|
||||||
{
|
|
||||||
get => BlockEngine.GetBlockInfo<TextLabelEntityViewStruct>(Id).textLabelComponent?.text;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref var text = ref BlockEngine.GetBlockInfo<TextLabelEntityViewStruct>(Id);
|
|
||||||
if (text.textLabelComponent != null) text.textLabelComponent.text = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the block exists. The other properties will return a default value if the block doesn't exist.
|
|
||||||
/// </summary>
|
|
||||||
public bool Exists => BlockEngine.BlockExists(Id);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns an array of blocks that are connected to this one. Returns an empty array if the block doesn't exist.
|
|
||||||
/// </summary>
|
|
||||||
public Block[] GetConnectedCubes() => BlockEngine.GetConnectedBlocks(Id);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes this block.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>True if the block exists and could be removed.</returns>
|
|
||||||
public bool Remove() => RemovalEngine.RemoveBlock(Id);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the rigid body of the cluster of blocks this one belongs to during simulation.
|
|
||||||
/// Can be used to apply forces or move the block around while the simulation is running.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The SimBody of the cluster</returns>
|
|
||||||
public SimBody GetSimBody()
|
|
||||||
{
|
|
||||||
uint id = BlockEngine.GetBlockInfo<GridConnectionsEntityStruct>(Id).machineRigidBodyId;
|
|
||||||
return new SimBody(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return $"{nameof(Id)}: {Id}, {nameof(Position)}: {Position}, {nameof(Type)}: {Type}, {nameof(Color)}: {Color}, {nameof(Exists)}: {Exists}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Init()
|
|
||||||
{
|
|
||||||
GameEngineManager.AddGameEngine(PlacementEngine);
|
|
||||||
GameEngineManager.AddGameEngine(MovementEngine);
|
|
||||||
GameEngineManager.AddGameEngine(RotationEngine);
|
|
||||||
GameEngineManager.AddGameEngine(RemovalEngine);
|
|
||||||
GameEngineManager.AddGameEngine(BlockEngine);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Convert the block to a specialised block class.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The block.</returns>
|
|
||||||
/// <typeparam name="T">The specialised block type.</typeparam>
|
|
||||||
public T Specialise<T>() where T : Block
|
|
||||||
{
|
|
||||||
// What have I gotten myself into?
|
|
||||||
// C# can't cast to a child of Block unless the object was originally that child type
|
|
||||||
// And C# doesn't let me make implicit cast operators for child types
|
|
||||||
// So thanks to Microsoft, we've got this horrible implementation using reflection
|
|
||||||
ConstructorInfo ctor = typeof(T).GetConstructor(types: new System.Type[] { typeof(EGID) });
|
|
||||||
if (ctor == null)
|
|
||||||
{
|
|
||||||
throw new BlockSpecializationException("Specialized block constructor does not accept an EGID");
|
|
||||||
}
|
|
||||||
return (T)ctor.Invoke(new object[] { Id });
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
public static EntitiesDB entitiesDB
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BlockEngine.GetEntitiesDB();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
namespace GamecraftModdingAPI.Blocks
|
|
||||||
{
|
|
||||||
public struct BlockColor
|
|
||||||
{
|
|
||||||
public BlockColors Color;
|
|
||||||
public byte Darkness;
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return $"{nameof(Color)}: {Color}, {nameof(Darkness)}: {Darkness}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Preset block colours
|
|
||||||
/// </summary>
|
|
||||||
public enum BlockColors
|
|
||||||
{
|
|
||||||
Default = byte.MaxValue,
|
|
||||||
White = 0,
|
|
||||||
Pink,
|
|
||||||
Purple,
|
|
||||||
Blue,
|
|
||||||
Aqua,
|
|
||||||
Green,
|
|
||||||
Lime,
|
|
||||||
Yellow,
|
|
||||||
Orange,
|
|
||||||
Red
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,152 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Gamecraft.Wires;
|
|
||||||
using RobocraftX.Blocks;
|
|
||||||
using RobocraftX.Common;
|
|
||||||
using RobocraftX.GUI.Hotbar.Colours;
|
|
||||||
using RobocraftX.Physics;
|
|
||||||
using RobocraftX.Scene.Simulation;
|
|
||||||
using Svelto.DataStructures;
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Engines;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Blocks
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Engine for executing general block actions
|
|
||||||
/// </summary>
|
|
||||||
public class BlockEngine : IApiEngine
|
|
||||||
{
|
|
||||||
public string Name { get; } = "GamecraftModdingAPIBlockGameEngine";
|
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { set; private get; }
|
|
||||||
|
|
||||||
public bool isRemovable => false;
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Ready()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public Block[] GetConnectedBlocks(EGID blockID)
|
|
||||||
{
|
|
||||||
if (!BlockExists(blockID)) return new Block[0];
|
|
||||||
Stack<uint> cubeStack = new Stack<uint>();
|
|
||||||
FasterList<uint> cubesToProcess = new FasterList<uint>();
|
|
||||||
ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID.entityID, cubeStack, cubesToProcess, (in GridConnectionsEntityStruct g) => { return false; });
|
|
||||||
var ret = new Block[cubesToProcess.count];
|
|
||||||
for (int i = 0; i < cubesToProcess.count; i++)
|
|
||||||
ret[i] = new Block(cubesToProcess[i]);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetBlockColorFromPalette(ref ColourParameterEntityStruct color)
|
|
||||||
{
|
|
||||||
ref var paletteEntry = ref entitiesDB.QueryEntity<PaletteEntryEntityStruct>(color.indexInPalette,
|
|
||||||
CommonExclusiveGroups.COLOUR_PALETTE_GROUP);
|
|
||||||
color.paletteColour = paletteEntry.Colour;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get a struct of a block. Can be used to set properties.
|
|
||||||
/// Returns a default value if not found.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="blockID">The block's ID</param>
|
|
||||||
/// <typeparam name="T">The struct to query</typeparam>
|
|
||||||
/// <returns>An editable reference to the struct</returns>
|
|
||||||
public ref T GetBlockInfo<T>(EGID blockID) where T : struct, IEntityComponent
|
|
||||||
{
|
|
||||||
if (entitiesDB.Exists<T>(blockID))
|
|
||||||
return ref entitiesDB.QueryEntity<T>(blockID);
|
|
||||||
T[] structHolder = new T[1]; //Create something that can be referenced
|
|
||||||
return ref structHolder[0]; //Gets a default value automatically
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get a struct of a block. Can be used to set properties.
|
|
||||||
/// Returns a default value if not found.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="blockID">The block's ID</param>
|
|
||||||
/// <param name="exists">Whether the specified struct exists for the block</param>
|
|
||||||
/// <typeparam name="T">The struct to query</typeparam>
|
|
||||||
/// <returns>An editable reference to the struct</returns>
|
|
||||||
public ref T GetBlockInfo<T>(EGID blockID, out bool exists) where T : struct, IEntityComponent
|
|
||||||
{
|
|
||||||
exists = entitiesDB.Exists<T>(blockID);
|
|
||||||
if (exists)
|
|
||||||
return ref entitiesDB.QueryEntity<T>(blockID);
|
|
||||||
T[] structHolder = new T[1];
|
|
||||||
//ref T defRef = ref structHolder[0];
|
|
||||||
return ref structHolder[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool BlockExists(EGID id)
|
|
||||||
{
|
|
||||||
return entitiesDB.Exists<DBEntityStruct>(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool GetBlockInfoExists<T>(EGID blockID) where T : struct, IEntityComponent
|
|
||||||
{
|
|
||||||
return entitiesDB.Exists<T>(blockID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SimBody[] GetSimBodiesFromID(byte id)
|
|
||||||
{
|
|
||||||
var ret = new FasterList<SimBody>(4);
|
|
||||||
if (!entitiesDB.HasAny<ObjectIdEntityStruct>(CommonExclusiveGroups.OWNED_BLOCKS_GROUP))
|
|
||||||
return new SimBody[0];
|
|
||||||
var oids = entitiesDB.QueryEntities<ObjectIdEntityStruct>(CommonExclusiveGroups.OWNED_BLOCKS_GROUP);
|
|
||||||
var connections = entitiesDB.QueryMappedEntities<GridConnectionsEntityStruct>(CommonExclusiveGroups.OWNED_BLOCKS_GROUP);
|
|
||||||
foreach (ref ObjectIdEntityStruct oid in oids)
|
|
||||||
{
|
|
||||||
if (oid.objectId != id) continue;
|
|
||||||
var rid = connections.Entity(oid.ID.entityID).machineRigidBodyId;
|
|
||||||
foreach (var rb in ret)
|
|
||||||
{
|
|
||||||
if (rb.Id.entityID == rid)
|
|
||||||
goto DUPLICATE; //Multiple Object Identifiers on one rigid body
|
|
||||||
}
|
|
||||||
ret.Add(new SimBody(rid));
|
|
||||||
DUPLICATE: ;
|
|
||||||
}
|
|
||||||
return ret.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObjectIdentifier[] GetObjectIDsFromID(byte id)
|
|
||||||
{
|
|
||||||
var ret = new FasterList<ObjectIdentifier>(4);
|
|
||||||
if (!entitiesDB.HasAny<ObjectIdEntityStruct>(CommonExclusiveGroups.OWNED_BLOCKS_GROUP))
|
|
||||||
return new ObjectIdentifier[0];
|
|
||||||
var oids = entitiesDB.QueryEntities<ObjectIdEntityStruct>(CommonExclusiveGroups.OWNED_BLOCKS_GROUP);
|
|
||||||
foreach (ref ObjectIdEntityStruct oid in oids)
|
|
||||||
if (oid.objectId == id)
|
|
||||||
ret.Add(new ObjectIdentifier(oid.ID));
|
|
||||||
return ret.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public SimBody[] GetConnectedSimBodies(uint id)
|
|
||||||
{
|
|
||||||
var joints = entitiesDB.QueryEntities<JointEntityStruct>(MachineSimulationGroups.JOINTS_GROUP);
|
|
||||||
var list = new FasterList<SimBody>(4);
|
|
||||||
foreach (var joint in joints)
|
|
||||||
{
|
|
||||||
if (joint.jointState == JointState.Broken) continue;
|
|
||||||
if (joint.connectedEntityA == id) list.Add(new SimBody(joint.connectedEntityB));
|
|
||||||
else if (joint.connectedEntityB == id) list.Add(new SimBody(joint.connectedEntityA));
|
|
||||||
}
|
|
||||||
|
|
||||||
return list.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
public EntitiesDB GetEntitiesDB()
|
|
||||||
{
|
|
||||||
return entitiesDB;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,239 +0,0 @@
|
||||||
namespace GamecraftModdingAPI.Blocks
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Possible block types
|
|
||||||
/// </summary>
|
|
||||||
public enum BlockIDs : ushort
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A custom value for the API. Doesn't exist for Gamecraft.
|
|
||||||
/// </summary>
|
|
||||||
Invalid = ushort.MaxValue,
|
|
||||||
AluminiumCube = 0,
|
|
||||||
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
|
|
||||||
GameOverBlock,
|
|
||||||
MovementConstrainer = 246,
|
|
||||||
RotationConstrainer,
|
|
||||||
AdvancedMovementDampener,
|
|
||||||
AdvancedRotationDampener,
|
|
||||||
Mover = 250,
|
|
||||||
Rotator,
|
|
||||||
MovementDampener,
|
|
||||||
RotationDampener,
|
|
||||||
AdvancedMover,
|
|
||||||
AdvancedRotator
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
using Svelto.ECS;
|
|
||||||
using RobocraftX.Common;
|
|
||||||
|
|
||||||
using HarmonyLib;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using RobocraftX.Blocks;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI;
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Blocks
|
|
||||||
{
|
|
||||||
public class ConsoleBlock : Block
|
|
||||||
{
|
|
||||||
public static ConsoleBlock PlaceNew(float3 position,
|
|
||||||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0,
|
|
||||||
int uscale = 1, float3 scale = default, Player player = null)
|
|
||||||
{
|
|
||||||
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
|
|
||||||
{
|
|
||||||
EGID id = PlacementEngine.PlaceBlock(BlockIDs.ConsoleBlock, color, darkness,
|
|
||||||
position, uscale, scale, player, rotation);
|
|
||||||
return new ConsoleBlock(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConsoleBlock(EGID id): base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<ConsoleBlockEntityStruct>(this.Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConsoleBlock(uint id): base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<ConsoleBlockEntityStruct>(this.Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// custom console block properties
|
|
||||||
|
|
||||||
public string Command
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BlockEngine.GetBlockInfo<ConsoleBlockEntityStruct>(Id).commandName;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
BlockEngine.GetBlockInfo<ConsoleBlockEntityStruct>(Id).commandName.Set(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Arg1
|
|
||||||
{
|
|
||||||
get => BlockEngine.GetBlockInfo<ConsoleBlockEntityStruct>(Id).arg1;
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
BlockEngine.GetBlockInfo<ConsoleBlockEntityStruct>(Id).arg1.Set(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Arg2
|
|
||||||
{
|
|
||||||
get => BlockEngine.GetBlockInfo<ConsoleBlockEntityStruct>(Id).arg2;
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
BlockEngine.GetBlockInfo<ConsoleBlockEntityStruct>(Id).arg2.Set(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Arg3
|
|
||||||
{
|
|
||||||
get => BlockEngine.GetBlockInfo<ConsoleBlockEntityStruct>(Id).arg3;
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
BlockEngine.GetBlockInfo<ConsoleBlockEntityStruct>(Id).arg3.Set(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using RobocraftX.Blocks;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Blocks
|
|
||||||
{
|
|
||||||
public class Motor : Block
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Places a new motor.
|
|
||||||
/// Any valid motor type is accepted.
|
|
||||||
/// This re-implements Block.PlaceNew(...)
|
|
||||||
/// </summary>
|
|
||||||
public static new Motor PlaceNew(BlockIDs block, float3 position,
|
|
||||||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0,
|
|
||||||
int uscale = 1, float3 scale = default, Player player = null)
|
|
||||||
{
|
|
||||||
if (!(block == BlockIDs.MotorS || block == BlockIDs.MotorM))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {typeof(Motor).Name} block");
|
|
||||||
}
|
|
||||||
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
|
|
||||||
{
|
|
||||||
EGID id = PlacementEngine.PlaceBlock(block, color, darkness,
|
|
||||||
position, uscale, scale, player, rotation);
|
|
||||||
return new Motor(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Motor(EGID id) : base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<MotorReadOnlyStruct>(this.Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Motor(uint id) : base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<MotorReadOnlyStruct>(this.Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// custom motor properties
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The motor's maximum rotational velocity.
|
|
||||||
/// </summary>
|
|
||||||
public float TopSpeed
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id).maxVelocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref MotorReadOnlyStruct motor = ref BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id);
|
|
||||||
motor.maxVelocity = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The motor's maximum rotational force.
|
|
||||||
/// </summary>
|
|
||||||
public float Torque
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id).maxForce;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref MotorReadOnlyStruct motor = ref BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id);
|
|
||||||
motor.maxForce = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The motor's direction.
|
|
||||||
/// </summary>
|
|
||||||
public bool Reverse
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id).reverse;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref MotorReadOnlyStruct motor = ref BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id);
|
|
||||||
motor.reverse = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
using RobocraftX.Common;
|
|
||||||
using RobocraftX.UECS;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Svelto.ECS.EntityStructs;
|
|
||||||
using Unity.Transforms;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
using GamecraftModdingAPI.Engines;
|
|
||||||
|
|
||||||
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 isRemovable => false;
|
|
||||||
|
|
||||||
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
|
|
||||||
});
|
|
||||||
entitiesDB.QueryEntity<GridConnectionsEntityStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP).isProcessed = false;
|
|
||||||
return posStruct.position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float3 GetPosition(uint blockID)
|
|
||||||
{
|
|
||||||
ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntity<PositionEntityStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP);
|
|
||||||
return posStruct.position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
using Gamecraft.Wires;
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Blocks
|
|
||||||
{
|
|
||||||
public class ObjectIdentifier : Block
|
|
||||||
{
|
|
||||||
public ObjectIdentifier(EGID id) : base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<ObjectIdEntityStruct>(Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObjectIdentifier(uint id) : base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<ObjectIdEntityStruct>(Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public char Identifier
|
|
||||||
{
|
|
||||||
get => (char) (BlockEngine.GetBlockInfo<ObjectIdEntityStruct>(Id).objectId + 'A');
|
|
||||||
set
|
|
||||||
{
|
|
||||||
BlockEngine.GetBlockInfo<ObjectIdEntityStruct>(Id).objectId = (byte) (value - 'A');
|
|
||||||
Label = value + ""; //The label isn't updated automatically
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Finds the identfier blocks with the given ID.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The ID to look for</param>
|
|
||||||
/// <returns>An array that may be empty</returns>
|
|
||||||
public static ObjectIdentifier[] GetByID(char id) => BlockEngine.GetObjectIDsFromID((byte) (id - 'A'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using RobocraftX.Blocks;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Blocks
|
|
||||||
{
|
|
||||||
public class Piston : Block
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Places a new piston.
|
|
||||||
/// Any valid piston type is accepted.
|
|
||||||
/// This re-implements Block.PlaceNew(...)
|
|
||||||
/// </summary>
|
|
||||||
public static new Piston PlaceNew(BlockIDs block, float3 position,
|
|
||||||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0,
|
|
||||||
int uscale = 1, float3 scale = default, Player player = null)
|
|
||||||
{
|
|
||||||
if (!(block == BlockIDs.ServoPiston || block == BlockIDs.StepperPiston || block == BlockIDs.PneumaticPiston))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {typeof(Piston).Name} block");
|
|
||||||
}
|
|
||||||
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
|
|
||||||
{
|
|
||||||
EGID id = PlacementEngine.PlaceBlock(block, color, darkness,
|
|
||||||
position, uscale, scale, player, rotation);
|
|
||||||
return new Piston(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Piston(EGID id) : base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<PistonReadOnlyStruct>(this.Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Piston(uint id) : base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<PistonReadOnlyStruct>(this.Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// custom piston properties
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The piston's max extension distance.
|
|
||||||
/// </summary>
|
|
||||||
public float MaximumExtension
|
|
||||||
{
|
|
||||||
get => BlockEngine.GetBlockInfo<PistonReadOnlyStruct>(Id).maxDeviation;
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref PistonReadOnlyStruct piston = ref BlockEngine.GetBlockInfo<PistonReadOnlyStruct>(Id);
|
|
||||||
piston.maxDeviation = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The piston's max extension force.
|
|
||||||
/// </summary>
|
|
||||||
public float MaximumForce
|
|
||||||
{
|
|
||||||
get => BlockEngine.GetBlockInfo<PistonReadOnlyStruct>(Id).maxForce;
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref PistonReadOnlyStruct piston = ref BlockEngine.GetBlockInfo<PistonReadOnlyStruct>(Id);
|
|
||||||
piston.maxForce = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,144 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
using DataLoader;
|
|
||||||
using HarmonyLib;
|
|
||||||
using RobocraftX.Blocks;
|
|
||||||
using RobocraftX.Blocks.Scaling;
|
|
||||||
using RobocraftX.Character;
|
|
||||||
using RobocraftX.Common;
|
|
||||||
using RobocraftX.CR.MachineEditing;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Svelto.ECS.EntityStructs;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
using GamecraftModdingAPI.Engines;
|
|
||||||
using GamecraftModdingAPI.Players;
|
|
||||||
|
|
||||||
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, Player player, 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,
|
|
||||||
(player ?? new Player(PlayerType.Local)).Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
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.NewUncheckedBlockEGID;
|
|
||||||
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";
|
|
||||||
|
|
||||||
public bool isRemovable => false;
|
|
||||||
|
|
||||||
[HarmonyPatch]
|
|
||||||
public class FactoryObtainerPatch
|
|
||||||
{
|
|
||||||
static void Postfix(BlockEntityFactory blockEntityFactory)
|
|
||||||
{
|
|
||||||
_blockEntityFactory = blockEntityFactory;
|
|
||||||
Logging.MetaDebugLog("Block entity factory injected.");
|
|
||||||
}
|
|
||||||
|
|
||||||
static MethodBase TargetMethod(Harmony instance)
|
|
||||||
{
|
|
||||||
return AccessTools.TypeByName("RobocraftX.CR.MachineEditing.PlaceBlockEngine").GetConstructors()[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
using HarmonyLib;
|
|
||||||
using RobocraftX.Blocks;
|
|
||||||
using RobocraftX.Common;
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
using GamecraftModdingAPI.Engines;
|
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { get; set; }
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name { get; } = "GamecraftModdingAPIRemovalGameEngine";
|
|
||||||
|
|
||||||
public bool isRemovable => false;
|
|
||||||
|
|
||||||
[HarmonyPatch]
|
|
||||||
public class FactoryObtainerPatch
|
|
||||||
{
|
|
||||||
static void Postfix(IEntityFunctions entityFunctions,
|
|
||||||
MachineGraphConnectionEntityFactory machineGraphConnectionEntityFactory)
|
|
||||||
{
|
|
||||||
_entityFunctions = entityFunctions;
|
|
||||||
_connectionFactory = machineGraphConnectionEntityFactory;
|
|
||||||
Logging.MetaDebugLog("Requirements injected.");
|
|
||||||
}
|
|
||||||
|
|
||||||
static MethodBase TargetMethod(Harmony instance)
|
|
||||||
{
|
|
||||||
return AccessTools.TypeByName("RobocraftX.CR.MachineEditing.RemoveBlockEngine").GetConstructors()[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
using RobocraftX.Common;
|
|
||||||
using RobocraftX.UECS;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Svelto.ECS.EntityStructs;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
using GamecraftModdingAPI.Engines;
|
|
||||||
|
|
||||||
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 isRemovable => false;
|
|
||||||
|
|
||||||
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
|
|
||||||
});
|
|
||||||
entitiesDB.QueryEntity<GridConnectionsEntityStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP).isProcessed = false;
|
|
||||||
return ((Quaternion)rotStruct.rotation).eulerAngles;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public float3 GetRotation(uint blockID)
|
|
||||||
{
|
|
||||||
ref RotationEntityStruct rotStruct = ref entitiesDB.QueryEntity<RotationEntityStruct>(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP);
|
|
||||||
return ((Quaternion) rotStruct.rotation).eulerAngles;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,110 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using RobocraftX.Blocks;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Blocks
|
|
||||||
{
|
|
||||||
public class Servo : Block
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Places a new servo.
|
|
||||||
/// Any valid servo type is accepted.
|
|
||||||
/// This re-implements Block.PlaceNew(...)
|
|
||||||
/// </summary>
|
|
||||||
public static new Servo PlaceNew(BlockIDs block, float3 position,
|
|
||||||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0,
|
|
||||||
int uscale = 1, float3 scale = default, Player player = null)
|
|
||||||
{
|
|
||||||
if (!(block == BlockIDs.ServoAxle || block == BlockIDs.ServoHinge || block == BlockIDs.ServoPiston))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {nameof(Servo)} block");
|
|
||||||
}
|
|
||||||
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
|
|
||||||
{
|
|
||||||
EGID id = PlacementEngine.PlaceBlock(block, color, darkness,
|
|
||||||
position, uscale, scale, player, rotation);
|
|
||||||
return new Servo(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Servo(EGID id) : base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<ServoReadOnlyStruct>(this.Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Servo(uint id) : base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<ServoReadOnlyStruct>(this.Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// custom servo properties
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The servo's minimum angle.
|
|
||||||
/// </summary>
|
|
||||||
public float MinimumAngle
|
|
||||||
{
|
|
||||||
get => BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id).minDeviation;
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id);
|
|
||||||
servo.minDeviation = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The servo's maximum angle.
|
|
||||||
/// </summary>
|
|
||||||
public float MaximumAngle
|
|
||||||
{
|
|
||||||
get => BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id).maxDeviation;
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id);
|
|
||||||
servo.maxDeviation = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The servo's maximum force.
|
|
||||||
/// </summary>
|
|
||||||
public float MaximumForce
|
|
||||||
{
|
|
||||||
get => BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id).maxForce;
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id);
|
|
||||||
servo.maxForce = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The servo's direction.
|
|
||||||
/// </summary>
|
|
||||||
public bool Reverse
|
|
||||||
{
|
|
||||||
get => BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id).reverse;
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id);
|
|
||||||
servo.reverse = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,204 +0,0 @@
|
||||||
using Svelto.ECS;
|
|
||||||
using Gamecraft.Wires;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Engines;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Blocks
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Engine which executes signal actions
|
|
||||||
/// </summary>
|
|
||||||
public class SignalEngine : IApiEngine
|
|
||||||
{
|
|
||||||
public const float POSITIVE_HIGH = 1.0f;
|
|
||||||
public const float NEGATIVE_HIGH = -1.0f;
|
|
||||||
public const float HIGH = 1.0f;
|
|
||||||
public const float ZERO = 0.0f;
|
|
||||||
|
|
||||||
public string Name { get; } = "GamecraftModdingAPISignalGameEngine";
|
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { set; private get; }
|
|
||||||
|
|
||||||
public bool isRemovable => false;
|
|
||||||
|
|
||||||
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 > POSITIVE_HIGH)
|
|
||||||
{
|
|
||||||
channelData.valueAsFloat = POSITIVE_HIGH;
|
|
||||||
}
|
|
||||||
else if (channelData.valueAsFloat < NEGATIVE_HIGH)
|
|
||||||
{
|
|
||||||
channelData.valueAsFloat = 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[] GetSignalInputs(EGID blockID)
|
|
||||||
{
|
|
||||||
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(blockID);
|
|
||||||
EGID[] inputs = new EGID[ports.inputCount];
|
|
||||||
for (uint i = 0; i < ports.inputCount; i++)
|
|
||||||
{
|
|
||||||
inputs[i] = new EGID(i + ports.firstInputID, NamedExclusiveGroup<InputPortsGroup>.Group);
|
|
||||||
}
|
|
||||||
return inputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EGID[] GetSignalOutputs(EGID blockID)
|
|
||||||
{
|
|
||||||
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(blockID);
|
|
||||||
EGID[] outputs = new EGID[ports.outputCount];
|
|
||||||
for (uint i = 0; i < ports.outputCount; i++)
|
|
||||||
{
|
|
||||||
outputs[i] = new EGID(i + ports.firstOutputID, NamedExclusiveGroup<OutputPortsGroup>.Group);
|
|
||||||
}
|
|
||||||
return outputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref WireEntityStruct MatchPortToWire(EGID portID, EGID blockID, out bool exists)
|
|
||||||
{
|
|
||||||
ref PortEntityStruct port = ref entitiesDB.QueryEntity<PortEntityStruct>(portID);
|
|
||||||
WireEntityStruct[] wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<WiresGroup>.Group).ToFastAccess(out uint count);
|
|
||||||
for (uint i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if ((wires[i].destinationPortUsage == port.usage && wires[i].destinationBlockEGID == blockID)
|
|
||||||
|| (wires[i].sourcePortUsage == port.usage && wires[i].sourceBlockEGID == blockID))
|
|
||||||
{
|
|
||||||
exists = true;
|
|
||||||
return ref wires[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exists = false;
|
|
||||||
WireEntityStruct[] defRef = new WireEntityStruct[1];
|
|
||||||
return ref defRef[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref ChannelDataStruct GetChannelDataStruct(EGID portID, out bool exists)
|
|
||||||
{
|
|
||||||
ref PortEntityStruct port = ref entitiesDB.QueryEntity<PortEntityStruct>(portID);
|
|
||||||
ChannelDataStruct[] channels = entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<ChannelDataGroup>.Group).ToFastAccess(out uint count);
|
|
||||||
if (port.firstChannelIndexCachedInSim < count)
|
|
||||||
{
|
|
||||||
exists = true;
|
|
||||||
return ref channels[port.firstChannelIndexCachedInSim];
|
|
||||||
}
|
|
||||||
exists = false;
|
|
||||||
ChannelDataStruct[] defRef = new ChannelDataStruct[1];
|
|
||||||
return ref defRef[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,123 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using Gamecraft.Wires;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI;
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Blocks
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Common implementation for blocks that support wiring.
|
|
||||||
/// </summary>
|
|
||||||
public class SignalingBlock : Block
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Places a new signaling block.
|
|
||||||
/// Any valid functional block type with IO ports will work.
|
|
||||||
/// This re-implements Block.PlaceNew(...)
|
|
||||||
/// </summary>
|
|
||||||
public static new SignalingBlock PlaceNew(BlockIDs block, float3 position,
|
|
||||||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0,
|
|
||||||
int uscale = 1, float3 scale = default, Player player = null)
|
|
||||||
{
|
|
||||||
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
|
|
||||||
{
|
|
||||||
EGID id = PlacementEngine.PlaceBlock(block, color, darkness,
|
|
||||||
position, uscale, scale, player, rotation);
|
|
||||||
return new SignalingBlock(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SignalingBlock(EGID id) : base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<BlockPortsStruct>(this.Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public SignalingBlock(uint id) : base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<BlockPortsStruct>(this.Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ref BlockPortsStruct GetBlockPortsStruct()
|
|
||||||
{
|
|
||||||
return ref BlockEngine.GetBlockInfo<BlockPortsStruct>(Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the input port identifiers.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The input identifiers.</returns>
|
|
||||||
protected EGID[] GetInputIds()
|
|
||||||
{
|
|
||||||
return SignalEngine.GetSignalInputs(Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the output port identifiers.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The output identifiers.</returns>
|
|
||||||
protected EGID[] GetOutputIds()
|
|
||||||
{
|
|
||||||
return SignalEngine.GetSignalOutputs(Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the port struct.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The port struct.</returns>
|
|
||||||
/// <param name="portId">Port identifier.</param>
|
|
||||||
protected ref PortEntityStruct GetPortStruct(EGID portId)
|
|
||||||
{
|
|
||||||
return ref BlockEngine.GetBlockInfo<PortEntityStruct>(portId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the connected wire.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The connected wire.</returns>
|
|
||||||
/// <param name="portId">Port identifier.</param>
|
|
||||||
/// <param name="connected">Whether the port has a wire connected to it.</param>
|
|
||||||
protected ref WireEntityStruct GetConnectedWire(EGID portId, out bool connected)
|
|
||||||
{
|
|
||||||
return ref SignalEngine.MatchPortToWire(portId, Id, out connected);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// [EXPERIMENTAL] Gets the channel data.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The channel data.</returns>
|
|
||||||
/// <param name="portId">Port identifier.</param>
|
|
||||||
/// <param name="exists">Whether the channel actually exists.</param>
|
|
||||||
protected ref ChannelDataStruct GetChannelData(EGID portId, out bool exists)
|
|
||||||
{
|
|
||||||
return ref SignalEngine.GetChannelDataStruct(portId, out exists);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The input port count.
|
|
||||||
/// </summary>
|
|
||||||
public uint InputCount
|
|
||||||
{
|
|
||||||
get => GetBlockPortsStruct().inputCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The output port count.
|
|
||||||
/// </summary>
|
|
||||||
public uint OutputCount
|
|
||||||
{
|
|
||||||
get => GetBlockPortsStruct().outputCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,124 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using RobocraftX.Blocks;
|
|
||||||
using Gamecraft.CharacterVulnerability;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI;
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Blocks
|
|
||||||
{
|
|
||||||
public class SpawnPoint : Block
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Places a new spawn point.
|
|
||||||
/// Any valid spawn block type is accepted.
|
|
||||||
/// This re-implements Block.PlaceNew(...)
|
|
||||||
/// </summary>
|
|
||||||
public static new SpawnPoint PlaceNew(BlockIDs block, float3 position,
|
|
||||||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0,
|
|
||||||
int uscale = 1, float3 scale = default, Player player = null)
|
|
||||||
{
|
|
||||||
if (!(block == BlockIDs.LargeSpawn || block == BlockIDs.SmallSpawn || block == BlockIDs.MediumSpawn || block == BlockIDs.PlayerSpawn))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {nameof(SpawnPoint)} block");
|
|
||||||
}
|
|
||||||
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
|
|
||||||
{
|
|
||||||
EGID id = PlacementEngine.PlaceBlock(block, color, darkness,
|
|
||||||
position, uscale, scale, player, rotation);
|
|
||||||
return new SpawnPoint(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SpawnPoint(EGID id) : base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<SpawnPointStatsEntityStruct>(this.Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public SpawnPoint(uint id) : base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<SpawnPointStatsEntityStruct>(this.Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// custom spawn point properties
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The lives the player spawns in with.
|
|
||||||
/// </summary>
|
|
||||||
public uint Lives
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id).lives;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref SpawnPointStatsEntityStruct spses = ref BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id);
|
|
||||||
spses.lives = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the spawned player can take damage.
|
|
||||||
/// </summary>
|
|
||||||
public bool Damageable
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id).canTakeDamage;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref SpawnPointStatsEntityStruct spses = ref BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id);
|
|
||||||
spses.canTakeDamage = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the game over screen will be displayed
|
|
||||||
/// </summary>
|
|
||||||
public bool GameOverEnabled
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id).gameOverScreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref SpawnPointStatsEntityStruct spses = ref BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id);
|
|
||||||
spses.gameOverScreen = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The team id for players who spawn here.
|
|
||||||
/// </summary>
|
|
||||||
public byte Team
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BlockEngine.GetBlockInfo<SpawnPointIdsEntityStruct>(Id).teamId;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref SpawnPointIdsEntityStruct spses = ref BlockEngine.GetBlockInfo<SpawnPointIdsEntityStruct>(Id);
|
|
||||||
spses.teamId = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using Gamecraft.Blocks.GUI;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI;
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Blocks
|
|
||||||
{
|
|
||||||
public class TextBlock : Block
|
|
||||||
{
|
|
||||||
|
|
||||||
public static TextBlock PlaceNew(float3 position,
|
|
||||||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0,
|
|
||||||
int uscale = 1, float3 scale = default, Player player = null)
|
|
||||||
{
|
|
||||||
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
|
|
||||||
{
|
|
||||||
EGID id = PlacementEngine.PlaceBlock(BlockIDs.TextBlock, color, darkness,
|
|
||||||
position, uscale, scale, player, rotation);
|
|
||||||
return new TextBlock(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextBlock(EGID id) : base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<TextBlockDataStruct>(this.Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextBlock(uint id) : base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<TextBlockDataStruct>(this.Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// custom text block properties
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The text block's current text.
|
|
||||||
/// </summary>
|
|
||||||
public string Text
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BlockEngine.GetBlockInfo<TextBlockDataStruct>(Id).textCurrent;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref TextBlockDataStruct tbds = ref BlockEngine.GetBlockInfo<TextBlockDataStruct>(Id);
|
|
||||||
tbds.textCurrent.Set(value);
|
|
||||||
tbds.textStored.Set(value);
|
|
||||||
BlockEngine.GetBlockInfo<TextBlockNetworkDataStruct>(Id).newTextBlockStringContent.Set(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The text block's current text block ID (used in ChangeTextBlockCommand).
|
|
||||||
/// </summary>
|
|
||||||
public string TextBlockId
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BlockEngine.GetBlockInfo<TextBlockDataStruct>(Id).textBlockID;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
BlockEngine.GetBlockInfo<TextBlockDataStruct>(Id).textBlockID.Set(value);
|
|
||||||
BlockEngine.GetBlockInfo<TextBlockNetworkDataStruct>(Id).newTextBlockID.Set(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,118 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using RobocraftX.Blocks;
|
|
||||||
using Gamecraft.Blocks.TimerBlock;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI;
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Blocks
|
|
||||||
{
|
|
||||||
public class Timer : Block
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Places a new timer block.
|
|
||||||
/// </summary>
|
|
||||||
public static Timer PlaceNew(float3 position,
|
|
||||||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0,
|
|
||||||
int uscale = 1, float3 scale = default, Player player = null)
|
|
||||||
{
|
|
||||||
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
|
|
||||||
{
|
|
||||||
EGID id = PlacementEngine.PlaceBlock(BlockIDs.Timer, color, darkness,
|
|
||||||
position, uscale, scale, player, rotation);
|
|
||||||
return new Timer(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Timer(EGID id) : base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<TimerBlockDataStruct>(this.Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Timer(uint id) : base(id)
|
|
||||||
{
|
|
||||||
if (!BlockEngine.GetBlockInfoExists<TimerBlockDataStruct>(this.Id))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// custom timer properties
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The player-specified start time.
|
|
||||||
/// </summary>
|
|
||||||
public float Start
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id).startTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref TimerBlockDataStruct tbds = ref BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id);
|
|
||||||
tbds.startTime = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The player-specified end time.
|
|
||||||
/// </summary>
|
|
||||||
public float End
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id).endTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref TimerBlockDataStruct tbds = ref BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id);
|
|
||||||
tbds.endTime = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether to display time with millisecond precision.
|
|
||||||
/// </summary>
|
|
||||||
public bool DisplayMilliseconds
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id).outputFormatHasMS;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref TimerBlockDataStruct tbds = ref BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id);
|
|
||||||
tbds.outputFormatHasMS = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Current time (as of the last video frame), in milliseconds.
|
|
||||||
/// </summary>
|
|
||||||
public int CurrentTime
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BlockEngine.GetBlockInfo<TimerBlockLabelCacheEntityStruct>(Id).timeLastRenderFrameMS;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
ref TimerBlockLabelCacheEntityStruct tblces = ref BlockEngine.GetBlockInfo<TimerBlockLabelCacheEntityStruct>(Id);
|
|
||||||
tblces.timeLastRenderFrameMS = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
using HarmonyLib;
|
|
||||||
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(Harmony instance)
|
|
||||||
{
|
|
||||||
return typeof(RobocraftX.GUI.CommandLine.CommandLineCompositionRoot).GetMethod("Compose").MakeGenericMethod(typeof(object));
|
|
||||||
//return func.Method;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using HarmonyLib;
|
|
||||||
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(Harmony harmonyInstance)
|
|
||||||
{
|
|
||||||
return AccessTools.Method(AccessTools.TypeByName("RobocraftX.StateSync.GameHostTransitionDeterministicGroupEngine"), "EndTransition");
|
|
||||||
//.MakeGenericMethod(typeof(CosmeticEnginesSequenceBuildOrder), typeof(CosmeticEnginesSequenceSimOrder), typeof(DeterministicToCosmeticSyncBuildOrder), typeof(DeterministicToCosmeticSyncSimOrder));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Events
|
|
||||||
{
|
|
||||||
public class EmitterBuilder
|
|
||||||
{
|
|
||||||
private string name;
|
|
||||||
|
|
||||||
private int? type;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new event emitter builder.
|
|
||||||
/// </summary>
|
|
||||||
public EmitterBuilder()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new event emitter builder.
|
|
||||||
/// This is equivalent to new <code>EmitterBuilder().Name(name)</code>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The emitter name.</param>
|
|
||||||
public EmitterBuilder(string name)
|
|
||||||
{
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create and return an event emitter builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The builder.</returns>
|
|
||||||
public static EmitterBuilder Builder()
|
|
||||||
{
|
|
||||||
return new EmitterBuilder();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create and return an event emitter builder.
|
|
||||||
/// This is equivalent to <code>Builder().Name(name)</code>
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The builder.</returns>
|
|
||||||
/// <param name="name">The emitter name.</param>
|
|
||||||
public static EmitterBuilder Builder(string name)
|
|
||||||
{
|
|
||||||
return new EmitterBuilder(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Name the event emitter.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The builder.</returns>
|
|
||||||
/// <param name="name">The event emitter name.</param>
|
|
||||||
public EmitterBuilder Name(string name)
|
|
||||||
{
|
|
||||||
this.name = name;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set the type of event to handle.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The builder.</returns>
|
|
||||||
/// <param name="eventType">The event type.</param>
|
|
||||||
public EmitterBuilder Handle(EventType eventType)
|
|
||||||
{
|
|
||||||
return Handle((int)eventType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set the type of event to handle.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The builder.</returns>
|
|
||||||
/// <param name="eventType">The event type.</param>
|
|
||||||
public EmitterBuilder Handle(int eventType)
|
|
||||||
{
|
|
||||||
this.type = eventType;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Build the event emitter.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The event emitter.</returns>
|
|
||||||
/// <param name="register">Automatically register the event emitter with EventManager.AddEventemitter().</param>
|
|
||||||
public IEventEmitterEngine Build(bool register = true)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(name))
|
|
||||||
{
|
|
||||||
throw new EventParameterMissingException("Event emitter name must be defined before Build() is called");
|
|
||||||
}
|
|
||||||
if (!type.HasValue)
|
|
||||||
{
|
|
||||||
throw new EventParameterMissingException("Event emitter event type must be defined before Build() is called");
|
|
||||||
}
|
|
||||||
SimpleEventEmitterEngine result = new SimpleEventEmitterEngine(type.Value, name);
|
|
||||||
if (register)
|
|
||||||
{
|
|
||||||
EventManager.AddEventEmitter(result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
using System;
|
|
||||||
namespace GamecraftModdingAPI.Events
|
|
||||||
{
|
|
||||||
public class EventException : GamecraftModdingAPIException
|
|
||||||
{
|
|
||||||
public EventException()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public EventException(string message) : base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public EventException(string message, Exception innerException) : base(message, innerException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EventNotFoundException : EventException
|
|
||||||
{
|
|
||||||
public EventNotFoundException()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public EventNotFoundException(string message) : base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EventAlreadyExistsException : EventException
|
|
||||||
{
|
|
||||||
public EventAlreadyExistsException()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public EventAlreadyExistsException(string message) : base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EventRuntimeException : EventException
|
|
||||||
{
|
|
||||||
public EventRuntimeException()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public EventRuntimeException(string message) : base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public EventRuntimeException(string message, Exception innerException) : base(message, innerException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EventParameterMissingException : EventException
|
|
||||||
{
|
|
||||||
public EventParameterMissingException()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public EventParameterMissingException(string message) : base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,128 +0,0 @@
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (ExistsEventHandler(engine))
|
|
||||||
{
|
|
||||||
throw new EventAlreadyExistsException($"IEventHandlerEngine {engine.Name} already exists");
|
|
||||||
}
|
|
||||||
_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)
|
|
||||||
{
|
|
||||||
if (ExistsEventEmitter(engine))
|
|
||||||
{
|
|
||||||
throw new EventAlreadyExistsException($"IEventEmitterEngine {engine.Name} already exists");
|
|
||||||
}
|
|
||||||
_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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using HarmonyLib;
|
|
||||||
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);
|
|
||||||
// initialize AsyncUtils
|
|
||||||
AsyncUtils.Setup(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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using HarmonyLib;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
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, IUnorderedInitializeOnTimeStoppedModeEntered
|
|
||||||
{
|
|
||||||
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.TimeStopped)
|
|
||||||
{
|
|
||||||
Emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public JobHandle OnInitializeTimeStoppedMode()
|
|
||||||
{
|
|
||||||
Emit();
|
|
||||||
return default(JobHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Ready() { }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
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, IUnorderedInitializeOnTimeRunningModeEntered
|
|
||||||
{
|
|
||||||
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.TimeRunning)
|
|
||||||
{
|
|
||||||
Emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public JobHandle OnInitializeTimeRunningMode()
|
|
||||||
{
|
|
||||||
Emit();
|
|
||||||
return default(JobHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Ready() { }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
using HarmonyLib;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,165 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Events
|
|
||||||
{
|
|
||||||
public class HandlerBuilder
|
|
||||||
{
|
|
||||||
private string name;
|
|
||||||
|
|
||||||
private int? type;
|
|
||||||
|
|
||||||
private Action<EntitiesDB> activated;
|
|
||||||
|
|
||||||
private Action<EntitiesDB> destroyed;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new event handler builder.
|
|
||||||
/// </summary>
|
|
||||||
public HandlerBuilder()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new event handler builder.
|
|
||||||
/// This is equivalent to new <code>HandlerBuilder().Name(name)</code>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The handler name.</param>
|
|
||||||
public HandlerBuilder(string name)
|
|
||||||
{
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create and return an event handler builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The builder.</returns>
|
|
||||||
public static HandlerBuilder Builder()
|
|
||||||
{
|
|
||||||
return new HandlerBuilder();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create and return an event handler builder.
|
|
||||||
/// This is equivalent to <code>Builder().Name(name)</code>
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The builder.</returns>
|
|
||||||
/// <param name="name">The handler name.</param>
|
|
||||||
public static HandlerBuilder Builder(string name)
|
|
||||||
{
|
|
||||||
return new HandlerBuilder(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Name the event handler.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The builder.</returns>
|
|
||||||
/// <param name="name">The event handler name.</param>
|
|
||||||
public HandlerBuilder Name(string name)
|
|
||||||
{
|
|
||||||
this.name = name;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set the action to perform on when the activated event occurs.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The builder.</returns>
|
|
||||||
/// <param name="action">The activated event action.</param>
|
|
||||||
public HandlerBuilder OnActivation(Action action)
|
|
||||||
{
|
|
||||||
return OnActivation((_) => { action(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set the action to perform on when the activated event occurs.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The builder.</returns>
|
|
||||||
/// <param name="action">The activated event action.</param>
|
|
||||||
public HandlerBuilder OnActivation(Action<EntitiesDB> action)
|
|
||||||
{
|
|
||||||
this.activated = action;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set the action to perform when the destroyed event occurs.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The builder.</returns>
|
|
||||||
/// <param name="action">The destroyed event action.</param>
|
|
||||||
public HandlerBuilder OnDestruction(Action action)
|
|
||||||
{
|
|
||||||
return OnDestruction((_) => { action(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set the action to perform when the destroyed event occurs.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The builder.</returns>
|
|
||||||
/// <param name="action">The destroyed event action.</param>
|
|
||||||
public HandlerBuilder OnDestruction(Action<EntitiesDB> action)
|
|
||||||
{
|
|
||||||
this.destroyed = action;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set the type of event to handle.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The builder.</returns>
|
|
||||||
/// <param name="eventType">The event type.</param>
|
|
||||||
public HandlerBuilder Handle(EventType eventType)
|
|
||||||
{
|
|
||||||
return Handle((int)eventType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set the type of event to handle.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The builder.</returns>
|
|
||||||
/// <param name="eventType">The event type.</param>
|
|
||||||
public HandlerBuilder Handle(int eventType)
|
|
||||||
{
|
|
||||||
this.type = eventType;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Build the event handler.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The event handler.</returns>
|
|
||||||
/// <param name="register">Automatically register the event handler with EventManager.AddEventHandler().</param>
|
|
||||||
public IEventHandlerEngine Build(bool register = true)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(name))
|
|
||||||
{
|
|
||||||
throw new EventParameterMissingException("Event handler name must be defined before Build() is called");
|
|
||||||
}
|
|
||||||
if (activated == null && destroyed == null)
|
|
||||||
{
|
|
||||||
throw new EventParameterMissingException("Event handler destruction or activated event action must be defined before Build() is called");
|
|
||||||
}
|
|
||||||
if (!type.HasValue)
|
|
||||||
{
|
|
||||||
throw new EventParameterMissingException("Event handler event type must be defined before Build() is called");
|
|
||||||
}
|
|
||||||
Action<EntitiesDB> validActivated = activated;
|
|
||||||
if (validActivated == null)
|
|
||||||
{
|
|
||||||
validActivated = (_) => { };
|
|
||||||
}
|
|
||||||
Action<EntitiesDB> validDestroyed = destroyed;
|
|
||||||
if (validDestroyed == null)
|
|
||||||
{
|
|
||||||
validDestroyed = (_) => { };
|
|
||||||
}
|
|
||||||
SimpleEventHandlerEngine result = new SimpleEventHandlerEngine(validActivated, validDestroyed, type.Value, name);
|
|
||||||
if (register)
|
|
||||||
{
|
|
||||||
EventManager.AddEventHandler(result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Engines;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Events
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Engine interface to create a ModEventEntityStruct in entitiesDB when a specific event occurs.
|
|
||||||
/// </summary>
|
|
||||||
public interface IEventEmitterEngine : IFactoryEngine
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Emit the event. (Optional)
|
|
||||||
/// </summary>
|
|
||||||
void Emit();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Svelto.ECS.Internal;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Engines;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Events
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Engine interface to handle ModEventEntityStruct events emitted by IEventEmitterEngines.
|
|
||||||
/// </summary>
|
|
||||||
public interface IEventHandlerEngine : IReactionaryEngine<ModEventEntityStruct>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using HarmonyLib;
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using HarmonyLib;
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
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>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
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; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,132 +0,0 @@
|
||||||
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 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 bool isRemovable => true;
|
|
||||||
|
|
||||||
public void Add(ref ModEventEntityStruct entityView, EGID egid)
|
|
||||||
{
|
|
||||||
if (entityView.type.Equals(this.type))
|
|
||||||
{
|
|
||||||
isActivated = true;
|
|
||||||
onActivatedInvokeCatchError(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;
|
|
||||||
if (handle && entitiesDB != null)
|
|
||||||
{
|
|
||||||
onActivatedInvokeCatchError(entitiesDB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Ready() { }
|
|
||||||
|
|
||||||
public void Remove(ref ModEventEntityStruct entityView, EGID egid)
|
|
||||||
{
|
|
||||||
if (entityView.type.Equals(this.type) && isActivated)
|
|
||||||
{
|
|
||||||
isActivated = false;
|
|
||||||
onDestroyedInvokeCatchError(entitiesDB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (isActivated)
|
|
||||||
{
|
|
||||||
isActivated = false;
|
|
||||||
onDestroyedInvokeCatchError(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onActivatedInvokeCatchError(EntitiesDB _entitiesDB)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
onActivated.Invoke(_entitiesDB);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
EventRuntimeException wrappedException = new EventRuntimeException($"EventHandler {Name} threw an exception when activated", e);
|
|
||||||
Logging.LogWarning(wrappedException.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onDestroyedInvokeCatchError(EntitiesDB _entitiesDB)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
onDestroyed.Invoke(_entitiesDB);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
EventRuntimeException wrappedException = new EventRuntimeException($"EventHandler {Name} threw an exception when destroyed", e);
|
|
||||||
Logging.LogWarning(wrappedException.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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) { }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,804 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net472</TargetFramework>
|
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
|
||||||
<Version>1.1.0</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="2.0.0.10" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="Microsoft.CSharp" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--Start Dependencies-->
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="IllusionInjector">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\IllusionInjector.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\IllusionInjector.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="IllusionPlugin">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\IllusionPlugin.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\IllusionPlugin.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="JWT">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\JWT.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\JWT.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Burst.Unsafe">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Burst.Unsafe.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Burst.Unsafe.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Facepunch.Steamworks.Win64">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Rewired_Core">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Rewired_Core.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Rewired_Core.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Rewired_Windows">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Rewired_Windows.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Rewired_Windows.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="mscorlib">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\mscorlib.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\mscorlib.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Newtonsoft.Json">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.AccessibilityModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AccessibilityModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AccessibilityModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.AIModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AIModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AIModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.AndroidJNIModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AndroidJNIModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AndroidJNIModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.AnimationModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.ARModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ARModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ARModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.AssetBundleModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AssetBundleModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AssetBundleModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.AudioModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.AudioModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.AudioModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.ClothModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ClothModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ClothModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.ClusterInputModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterInputModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterInputModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.ClusterRendererModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterRendererModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterRendererModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.CoreModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.CrashReportingModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.CrashReportingModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.CrashReportingModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.DirectorModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.DirectorModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.DirectorModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.DSPGraphModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.DSPGraphModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.DSPGraphModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.GameCenterModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.GameCenterModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.GameCenterModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.GridModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.GridModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.GridModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.HotReloadModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.HotReloadModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.HotReloadModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.ImageConversionModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ImageConversionModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ImageConversionModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.IMGUIModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.InputLegacyModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.InputModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.InputModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.InputModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.JSONSerializeModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.JSONSerializeModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.JSONSerializeModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.LocalizationModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.LocalizationModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.LocalizationModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.ParticleSystemModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ParticleSystemModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ParticleSystemModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.PerformanceReportingModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.PerformanceReportingModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.PerformanceReportingModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.Physics2DModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.Physics2DModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.Physics2DModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.PhysicsModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.ProfilerModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ProfilerModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ProfilerModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.ScreenCaptureModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.ScreenCaptureModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.ScreenCaptureModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.SharedInternalsModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SharedInternalsModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.SharedInternalsModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.SpriteMaskModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteMaskModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteMaskModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.SpriteShapeModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteShapeModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteShapeModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.StreamingModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.StreamingModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.StreamingModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.SubstanceModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SubstanceModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.SubstanceModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.SubsystemsModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.SubsystemsModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.SubsystemsModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.TerrainModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.TerrainPhysicsModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainPhysicsModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainPhysicsModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.TextCoreModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TextCoreModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TextCoreModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.TextRenderingModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.TilemapModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TilemapModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TilemapModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.TLSModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.TLSModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.TLSModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UIElementsModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UIElementsModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UIElementsModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UIModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UIModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UIModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UmbraModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UmbraModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UmbraModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UNETModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UNETModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UNETModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UnityAnalyticsModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityAnalyticsModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityAnalyticsModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UnityConnectModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityConnectModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityConnectModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UnityTestProtocolModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityTestProtocolModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityTestProtocolModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UnityWebRequestAssetBundleModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAssetBundleModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAssetBundleModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UnityWebRequestAudioModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UnityWebRequestModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UnityWebRequestTextureModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UnityWebRequestWWWModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.VehiclesModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VehiclesModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.VehiclesModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.VFXModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VFXModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.VFXModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.VideoModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VideoModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.VideoModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.VRModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.VRModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.VRModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.WindModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.WindModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.WindModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.XRModule">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.XRModule.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.XRModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Analytics">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Analytics.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Analytics.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Assembly-CSharp-firstpass">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Assembly-CSharp">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Assembly-CSharp.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Assembly-CSharp.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Authentication">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Authentication.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Authentication.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="BlockEntityFactory">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\BlockEntityFactory.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\BlockEntityFactory.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Blocks.HUDFeedbackBlocks">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Blocks.HUDFeedbackBlocks.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Blocks.HUDFeedbackBlocks.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="ChannelsCommon">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\ChannelsCommon.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\ChannelsCommon.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="ClusterToWireConversion.Mock">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\ClusterToWireConversion.Mock.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\ClusterToWireConversion.Mock.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="CommandLine">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\CommandLine.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\CommandLine.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="DataLoader">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\DataLoader.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\DataLoader.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="DDNA">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\DDNA.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\DDNA.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="FMOD">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\FMOD.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\FMOD.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="FullGame">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\FullGame.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\FullGame.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.Blocks.ConsoleBlock">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.ConsoleBlock.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.ConsoleBlock.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.Blocks.GenericPhysicsBlocks">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.GenericPhysicsBlocks.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.GenericPhysicsBlocks.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.Blocks.LogicBlock">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.LogicBlock.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.LogicBlock.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.Blocks.TimerBlock">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TimerBlock.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TimerBlock.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.CharacterVulnerability">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerability.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerability.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.CharacterVulnerabilityGui">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerabilityGui.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerabilityGui.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.Effects">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Effects.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Effects.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.GUI.ConsoleBlock">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.ConsoleBlock.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.ConsoleBlock.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.GUI.GraphicsScreen">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.GraphicsScreen.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.GraphicsScreen.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.GUI.HUDFeedbackBlocks">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.HUDFeedbackBlocks.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.HUDFeedbackBlocks.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.GUI.Tweaks">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Tweaks.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Tweaks.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.GUI.Wires">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Wires.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Wires.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.GUI.Wires.Mockup">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Wires.Mockup.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Wires.Mockup.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.GUI.WorldSpaceGuis">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.WorldSpaceGuis.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.WorldSpaceGuis.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.Tweaks">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.Tweaks.Mockup">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.Mockup.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.Mockup.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.Wires">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.Wires.Input">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Input.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Input.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gamecraft.Wires.Mockup">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Mockup.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Mockup.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="GameState">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\GameState.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\GameState.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="GPUInstancer">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\GPUInstancer.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\GPUInstancer.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Havok.Physics">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Havok.Physics.dll</HintPath>
|
|
||||||
<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>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Havok.Physics.Hybrid.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="LZ4">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\LZ4.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\LZ4.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="MultiplayerNetworking">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\MultiplayerNetworking.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\MultiplayerNetworking.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="MultiplayerTest">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\MultiplayerTest.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\MultiplayerTest.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RCX.ScreenshotTaker">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RCX.ScreenshotTaker.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RCX.ScreenshotTaker.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.AccountPreferences">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.AccountPreferences.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.AccountPreferences.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.Blocks">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Blocks.dll</HintPath>
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.Blocks.Triggers.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.Building.BoxSelect">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Building.BoxSelect.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.Building.BoxSelect.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.Building.Jobs">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Building.Jobs.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.Building.Jobs.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.Character">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Character.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.Character.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.ClusterToWireConversion">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.ClusterToWireConversion.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.ClusterToWireConversion.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.Common">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Common.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.Common.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.ControlsScreen">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.ControlsScreen.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.ControlsScreen.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.Crosshair">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Crosshair.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.Crosshair.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.FrontEnd">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.FrontEnd.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.FrontEnd.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.GUI.BlockLabel">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.BlockLabel.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.BlockLabel.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.GUI.DebugDisplay">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.DebugDisplay.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.DebugDisplay.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.GUI">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.dll</HintPath>
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUIs.WorkshopPrefabs.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.Input">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Input.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.Input.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.MachineEditor">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.MachineEditor.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.MachineEditor.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.MainGame">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.MainGame.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.MainGame.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.MainSimulation">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.MainSimulation.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.MainSimulation.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.MockCharacter">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.MockCharacter.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.MockCharacter.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.Multiplayer">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Multiplayer.dll</HintPath>
|
|
||||||
<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>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.Multiplayer.NetworkEntityStream.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.MultiplayerInput">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.MultiplayerInput.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.MultiplayerInput.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Robocraftx.ObjectIdBlocks">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Robocraftx.ObjectIdBlocks.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Robocraftx.ObjectIdBlocks.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.Party">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Party.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.Party.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.PartyGui">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.PartyGui.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.PartyGui.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.Physics">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Physics.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.Physics.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.PilotSeat">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.PilotSeat.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.PilotSeat.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.Player">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Player.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.Player.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.Rendering">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Rendering.dll</HintPath>
|
|
||||||
<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>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.Rendering.Mock.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.SaveAndLoad">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.SaveAndLoad.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.SaveAndLoad.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.SaveGameDialog">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.SaveGameDialog.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.SaveGameDialog.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.Serializers">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Serializers.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.Serializers.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.Services">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.Services.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.Services.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.SignalHandling">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.SignalHandling.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.SignalHandling.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX.StateSync">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX.StateSync.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX.StateSync.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX_SpawnPoints">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX_SpawnPoints.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX_SpawnPoints.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocraftX_TextBlock">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocraftX_TextBlock.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocraftX_TextBlock.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="RobocratX.SimulationCompositionRoot">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\RobocratX.SimulationCompositionRoot.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\RobocratX.SimulationCompositionRoot.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="StringFormatter">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\StringFormatter.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\StringFormatter.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Svelto.Common_3">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.Common_3.dll</HintPath>
|
|
||||||
<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>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Svelto.ECS.Debugger.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Svelto.ECS.Debugger.Internal">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.ECS.Debugger.Internal.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Svelto.ECS.Debugger.Internal.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Svelto.ECS">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.ECS.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Svelto.ECS.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Svelto.Services">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.Services.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Svelto.Services.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Svelto.Tasks">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.Tasks.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Svelto.Tasks.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Addressables">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Addressables.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Addressables.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Burst">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Burst.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Burst.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Collections">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Collections.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Collections.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Deformations">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Deformations.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Deformations.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Entities">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Entities.dll</HintPath>
|
|
||||||
<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>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Entities.Hybrid.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Jobs">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Jobs.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Jobs.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Mathematics">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Mathematics.dll</HintPath>
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Physics.Hybrid.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Platforms.Common">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Platforms.Common.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Platforms.Common.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Postprocessing.Runtime">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Postprocessing.Runtime.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Postprocessing.Runtime.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Properties">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Properties.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Properties.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Properties.Reflection">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Properties.Reflection.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Properties.Reflection.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Properties.UI">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Properties.UI.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Properties.UI.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.RenderPipeline.Universal.ShaderLibrary">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.RenderPipeline.Universal.ShaderLibrary.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.RenderPipeline.Universal.ShaderLibrary.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.RenderPipelines.Core.Runtime">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.Core.Runtime.dll</HintPath>
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.RenderPipelines.Universal.Runtime">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.Universal.Runtime.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.Universal.Runtime.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.RenderPipelines.Universal.Shaders">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.Universal.Shaders.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.Universal.Shaders.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.ResourceManager">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.ResourceManager.dll</HintPath>
|
|
||||||
<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>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Scenes.Hybrid.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.ScriptableBuildPipeline">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.ScriptableBuildPipeline.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.ScriptableBuildPipeline.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Serialization">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Serialization.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Serialization.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.TextMeshPro">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.TextMeshPro.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.TextMeshPro.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Timeline">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Timeline.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Timeline.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Transforms">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\Unity.Transforms.dll</HintPath>
|
|
||||||
<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>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\Unity.Transforms.Hybrid.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UI">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\UnityEngine.UI.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\UnityEngine.UI.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="uREPL">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\uREPL.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\uREPL.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="VisualProfiler">
|
|
||||||
<HintPath>..\ref\Gamecraft_Data\Managed\VisualProfiler.dll</HintPath>
|
|
||||||
<HintPath>..\..\ref\Gamecraft_Data\Managed\VisualProfiler.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
|
||||||
<!--End Dependencies-->
|
|
||||||
|
|
||||||
</Project>
|
|
|
@ -1,24 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.Serialization;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI
|
|
||||||
{
|
|
||||||
public class GamecraftModdingAPIException : Exception
|
|
||||||
{
|
|
||||||
public GamecraftModdingAPIException()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public GamecraftModdingAPIException(string message) : base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public GamecraftModdingAPIException(string message, Exception innerException) : base(message, innerException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected GamecraftModdingAPIException(SerializationInfo info, StreamingContext context) : base(info, context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,153 +0,0 @@
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using RobocraftX.Common.Input;
|
|
||||||
using RobocraftX.Players;
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
using GamecraftModdingAPI.Engines;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Input
|
|
||||||
{
|
|
||||||
public class FakeInputEngine : IApiEngine
|
|
||||||
{
|
|
||||||
public string Name { get; } = "GamecraftModdingAPIFakeInputEngine";
|
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { set; private get; }
|
|
||||||
|
|
||||||
public bool isRemovable => false;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using RobocraftX.Common.Input;
|
|
||||||
using RobocraftX.Multiplayer.Input;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Blocks;
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
using HarmonyLib;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using RobocraftX.Character;
|
|
||||||
using RobocraftX.GUI.Hotbar;
|
|
||||||
using RobocraftX.Players;
|
|
||||||
using RobocraftX.Common;
|
|
||||||
using RobocraftX.Common.Input;
|
|
||||||
using RobocraftX.Common.Players;
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Blocks;
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
using GamecraftModdingAPI.Engines;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Inventory
|
|
||||||
{
|
|
||||||
public class HotbarEngine : IApiEngine
|
|
||||||
{
|
|
||||||
public string Name { get; } = "GamecraftModdingAPIHotbarGameEngine";
|
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { set; private get; }
|
|
||||||
|
|
||||||
public bool isRemovable => false;
|
|
||||||
|
|
||||||
public bool IsInGame = false;
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
IsInGame = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Ready()
|
|
||||||
{
|
|
||||||
IsInGame = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SelectBlock(int block, uint playerID, bool cubeSelectedByPick = false)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
using RobocraftX.GUI;
|
|
||||||
using RobocraftX.GUI.Hotbar;
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
using HarmonyLib;
|
|
||||||
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(Harmony harmonyInstance)
|
|
||||||
{
|
|
||||||
return PatchedMethod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
using HarmonyLib;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
using GamecraftModdingAPI.Events;
|
|
||||||
using GamecraftModdingAPI.Players;
|
|
||||||
using GamecraftModdingAPI.Tasks;
|
|
||||||
using uREPL;
|
|
||||||
|
|
||||||
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 Harmony 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 = new Harmony(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");
|
|
||||||
// init inventory
|
|
||||||
Inventory.Hotbar.Init();
|
|
||||||
// init input
|
|
||||||
Input.FakeInput.Init();
|
|
||||||
// init object-oriented classes
|
|
||||||
Player.Init();
|
|
||||||
Block.Init();
|
|
||||||
GameClient.Init();
|
|
||||||
AsyncUtils.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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using RobocraftX.SaveAndLoad;
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
using HarmonyLib;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Persistence
|
|
||||||
{
|
|
||||||
[HarmonyPatch(typeof(SaveAndLoadCompositionRoot), "Compose")]
|
|
||||||
class SaveAndLoadCompositionRootPatch
|
|
||||||
{
|
|
||||||
public static EnginesRoot currentEnginesRoot;
|
|
||||||
|
|
||||||
public static void Prefix(EnginesRoot enginesRoot)
|
|
||||||
{
|
|
||||||
currentEnginesRoot = enginesRoot;
|
|
||||||
//SerializerManager.RegisterSerializers(enginesRoot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,255 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using Unity.Mathematics;
|
|
||||||
using RobocraftX.Common;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Players;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An in-game player character. Any Leo you see is a player.
|
|
||||||
/// </summary>
|
|
||||||
public class Player
|
|
||||||
{
|
|
||||||
// static functionality
|
|
||||||
private static PlayerEngine playerEngine = new PlayerEngine();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the specified player exists.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Whether the player exists.</returns>
|
|
||||||
/// <param name="player">Player type.</param>
|
|
||||||
public static bool Exists(PlayerType player)
|
|
||||||
{
|
|
||||||
switch (player)
|
|
||||||
{
|
|
||||||
case PlayerType.Remote:
|
|
||||||
return playerEngine.GetRemotePlayer() != uint.MaxValue;
|
|
||||||
case PlayerType.Local:
|
|
||||||
return playerEngine.GetLocalPlayer() != uint.MaxValue;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the specified player exists.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Whether the player exists.</returns>
|
|
||||||
/// <param name="player">The player's unique identifier.</param>
|
|
||||||
public static bool Exists(uint player)
|
|
||||||
{
|
|
||||||
return playerEngine.ExistsById(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="T:GamecraftModdingAPI.Player"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The player's unique identifier.</param>
|
|
||||||
public Player(uint id)
|
|
||||||
{
|
|
||||||
this.Id = id;
|
|
||||||
if (!Exists(id))
|
|
||||||
{
|
|
||||||
throw new PlayerNotFoundException($"No player with id {id} exists");
|
|
||||||
}
|
|
||||||
this.Type = playerEngine.GetLocalPlayer() == id ? PlayerType.Local : PlayerType.Remote;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="T:GamecraftModdingAPI.Player"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="player">The player type. Chooses the first available player matching the criteria.</param>
|
|
||||||
public Player(PlayerType player)
|
|
||||||
{
|
|
||||||
uint localId = playerEngine.GetLocalPlayer();
|
|
||||||
switch (player)
|
|
||||||
{
|
|
||||||
case PlayerType.Local:
|
|
||||||
this.Id = playerEngine.GetLocalPlayer();
|
|
||||||
break;
|
|
||||||
case PlayerType.Remote:
|
|
||||||
this.Id = playerEngine.GetRemotePlayer();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (this.Id == uint.MaxValue)
|
|
||||||
{
|
|
||||||
throw new PlayerNotFoundException($"No player of {player} type exists");
|
|
||||||
}
|
|
||||||
this.Type = player;
|
|
||||||
}
|
|
||||||
|
|
||||||
// object fields & properties
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The player's type.
|
|
||||||
/// The player type is always relative to the current client, not the game host.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The enumerated player type.</value>
|
|
||||||
public PlayerType Type { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The player's unique identifier.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The identifier.</value>
|
|
||||||
public uint Id { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The player's current position.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The position.</value>
|
|
||||||
public float3 Position
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return playerEngine.GetLocation(Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
playerEngine.SetLocation(Id, value, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The player's current rotation.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The rotation.</value>
|
|
||||||
public quaternion Rotation
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return playerEngine.GetRotation(Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
playerEngine.SetRotation(Id, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The player's current velocity.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The velocity.</value>
|
|
||||||
public float3 Velocity
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return playerEngine.GetLinearVelocity(Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
playerEngine.SetLinearVelocity(Id, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The player's current angular velocity.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The angular velocity.</value>
|
|
||||||
public float3 AngularVelocity
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return playerEngine.GetAngularVelocity(Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
playerEngine.SetAngularVelocity(Id, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The player's mass.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The mass.</value>
|
|
||||||
public float Mass
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return 1f / playerEngine.GetMass(Id).InverseMass;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Setting mass doesn't do anything
|
|
||||||
/*set
|
|
||||||
{
|
|
||||||
playerEngine.SetInverseMass(Id, 1f / value);
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
private float _ping = -1f;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The player's latest network ping time.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The ping (s).</value>
|
|
||||||
public float Ping
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
float? temp = playerEngine.GetLastPingTime(Id, Type);
|
|
||||||
if (temp.HasValue)
|
|
||||||
{
|
|
||||||
_ping = temp.Value;
|
|
||||||
}
|
|
||||||
return _ping;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// object methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Teleport the player to the specified coordinates.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">The x coordinate.</param>
|
|
||||||
/// <param name="y">The y coordinate.</param>
|
|
||||||
/// <param name="z">The z coordinate.</param>
|
|
||||||
/// <param name="relative">If set to <c>true</c> teleport relative to the player's current position.</param>
|
|
||||||
/// <param name="exitSeat">If set to <c>true</c> exit any seat the player is in.</param>
|
|
||||||
public void Teleport(float x, float y, float z, bool relative = true, bool exitSeat = true)
|
|
||||||
{
|
|
||||||
float3 location = new float3(x, y, z);
|
|
||||||
if (relative)
|
|
||||||
{
|
|
||||||
location += playerEngine.GetLocation(Id);
|
|
||||||
}
|
|
||||||
playerEngine.SetLocation(Id, location, exitSeat: exitSeat);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the block the player is currently looking at.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="maxDistance">The maximum distance from the player (default is the player's building reach)</param>
|
|
||||||
/// <returns>The block or null if not found</returns>
|
|
||||||
public Block GetBlockLookedAt(float maxDistance = -1f)
|
|
||||||
{
|
|
||||||
var egid = playerEngine.GetThingLookedAt(Id, maxDistance);
|
|
||||||
return egid.HasValue && egid.Value.groupID == CommonExclusiveGroups.OWNED_BLOCKS_GROUP
|
|
||||||
? new Block(egid.Value)
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the rigid body the player is currently looking at during simulation.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="maxDistance">The maximum distance from the player (default is the player's building reach)</param>
|
|
||||||
/// <returns>The block or null if not found</returns>
|
|
||||||
public SimBody GetSimBodyLookedAt(float maxDistance = -1f)
|
|
||||||
{
|
|
||||||
var egid = playerEngine.GetThingLookedAt(Id, maxDistance);
|
|
||||||
return egid.HasValue && egid.Value.groupID == CommonExclusiveGroups.SIMULATION_BODIES_GROUP
|
|
||||||
? new SimBody(egid.Value)
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// internal methods
|
|
||||||
|
|
||||||
public static void Init()
|
|
||||||
{
|
|
||||||
Utility.GameEngineManager.AddGameEngine(playerEngine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,256 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
using RobocraftX.Character;
|
|
||||||
using RobocraftX.Character.Movement;
|
|
||||||
using RobocraftX.Common.Players;
|
|
||||||
using RobocraftX.Common.Input;
|
|
||||||
using RobocraftX.Physics;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
using Unity.Physics;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Engines;
|
|
||||||
using RobocraftX.Blocks.Ghost;
|
|
||||||
using RobocraftX.Character.Camera;
|
|
||||||
using RobocraftX.Character.Factories;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Players
|
|
||||||
{
|
|
||||||
internal class PlayerEngine : IApiEngine
|
|
||||||
{
|
|
||||||
public string Name { get; } = "GamecraftModdingAPIPlayerGameEngine";
|
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { set; private get; }
|
|
||||||
|
|
||||||
public bool isRemovable => false;
|
|
||||||
|
|
||||||
private bool isReady = false;
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
isReady = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Ready()
|
|
||||||
{
|
|
||||||
isReady = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint GetLocalPlayer()
|
|
||||||
{
|
|
||||||
if (!isReady) return uint.MaxValue;
|
|
||||||
PlayerIDStruct[] localPlayers = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.LocalPlayers).ToFastAccess(out uint count);
|
|
||||||
if (count > 0)
|
|
||||||
{
|
|
||||||
return localPlayers[0].ID.entityID;
|
|
||||||
}
|
|
||||||
return uint.MaxValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint GetRemotePlayer()
|
|
||||||
{
|
|
||||||
if (!isReady) return uint.MaxValue;
|
|
||||||
PlayerIDStruct[] localPlayers = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.RemotePlayers).ToFastAccess(out uint count);
|
|
||||||
if (count > 0)
|
|
||||||
{
|
|
||||||
return localPlayers[0].ID.entityID;
|
|
||||||
}
|
|
||||||
return uint.MaxValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ExistsById(uint playerId)
|
|
||||||
{
|
|
||||||
PlayerIDStruct[] players = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.LocalPlayers).ToFastAccess(out uint count);
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if (players[i].ID.entityID == playerId)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
players = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.RemotePlayers).ToFastAccess(out count);
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if (players[i].ID.entityID == playerId)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float3 GetLocation(uint playerId)
|
|
||||||
{
|
|
||||||
if (GetCharacterStruct<RigidBodyEntityStruct>(playerId, out RigidBodyEntityStruct rbes))
|
|
||||||
{
|
|
||||||
return rbes.position;
|
|
||||||
}
|
|
||||||
return float3.zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetLocation(uint playerId, float3 location, bool exitSeat = true)
|
|
||||||
{
|
|
||||||
ExclusiveGroup[] characterGroups = CharacterExclusiveGroups.AllCharacters;
|
|
||||||
for (int i = 0; i < characterGroups.Length; i++)
|
|
||||||
{
|
|
||||||
EGID egid = new EGID(playerId, characterGroups[i]);
|
|
||||||
if (entitiesDB.Exists<RigidBodyEntityStruct>(egid))
|
|
||||||
{
|
|
||||||
ref RigidBodyEntityStruct rbes = ref entitiesDB.QueryEntity<RigidBodyEntityStruct>(egid);
|
|
||||||
if (characterGroups[i] == CharacterExclusiveGroups.InPilotSeatGroup && exitSeat)
|
|
||||||
{
|
|
||||||
entitiesDB.QueryEntity<CharacterPilotSeatEntityStruct>(egid).instantExit = true;
|
|
||||||
entitiesDB.PublishEntityChange<CharacterPilotSeatEntityStruct>(egid);
|
|
||||||
}
|
|
||||||
rbes.position = location;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public quaternion GetRotation(uint playerId)
|
|
||||||
{
|
|
||||||
if (GetCharacterStruct<RigidBodyEntityStruct>(playerId, out RigidBodyEntityStruct rbes))
|
|
||||||
{
|
|
||||||
return rbes.rotation;
|
|
||||||
}
|
|
||||||
return quaternion.identity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetRotation(uint playerId, quaternion value)
|
|
||||||
{
|
|
||||||
if (GetCharacterStruct<RigidBodyEntityStruct>(playerId, out RigidBodyEntityStruct rbes))
|
|
||||||
{
|
|
||||||
rbes.rotation = value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float3 GetLinearVelocity(uint playerId)
|
|
||||||
{
|
|
||||||
if (GetCharacterStruct<RigidBodyEntityStruct>(playerId, out RigidBodyEntityStruct rbes))
|
|
||||||
{
|
|
||||||
return rbes.velocity;
|
|
||||||
}
|
|
||||||
return float3.zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetLinearVelocity(uint playerId, float3 value)
|
|
||||||
{
|
|
||||||
if (GetCharacterStruct<RigidBodyEntityStruct>(playerId, out RigidBodyEntityStruct rbes))
|
|
||||||
{
|
|
||||||
rbes.velocity = value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float3 GetAngularVelocity(uint playerId)
|
|
||||||
{
|
|
||||||
if (GetCharacterStruct<RigidBodyEntityStruct>(playerId, out RigidBodyEntityStruct rbes))
|
|
||||||
{
|
|
||||||
return rbes.angularVelocity;
|
|
||||||
}
|
|
||||||
return float3.zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetAngularVelocity(uint playerId, float3 value)
|
|
||||||
{
|
|
||||||
if (GetCharacterStruct<RigidBodyEntityStruct>(playerId, out RigidBodyEntityStruct rbes))
|
|
||||||
{
|
|
||||||
rbes.angularVelocity = value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PhysicsMass GetMass(uint playerId)
|
|
||||||
{
|
|
||||||
if (GetCharacterStruct<RigidBodyEntityStruct>(playerId, out RigidBodyEntityStruct rbes))
|
|
||||||
{
|
|
||||||
return rbes.physicsMass;
|
|
||||||
}
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetInverseMass(uint playerId, float inverseMass)
|
|
||||||
{
|
|
||||||
if (GetCharacterStruct<RigidBodyEntityStruct>(playerId, out RigidBodyEntityStruct rbes))
|
|
||||||
{
|
|
||||||
rbes.physicsMass.InverseInertia = inverseMass;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float? GetLastPingTime(uint playerId, PlayerType type)
|
|
||||||
{
|
|
||||||
EGID egid = new EGID(playerId, GroupFromEnum(type));
|
|
||||||
if (entitiesDB.Exists<PlayerNetworkStatsEntityStruct>(egid))
|
|
||||||
{
|
|
||||||
return entitiesDB.QueryEntity<PlayerNetworkStatsEntityStruct>(egid).lastPingTimeSinceLevelLoad;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// reusable methods
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private ExclusiveGroup GroupFromEnum(PlayerType type)
|
|
||||||
{
|
|
||||||
return type == PlayerType.Local ? PlayersExclusiveGroups.LocalPlayers : PlayersExclusiveGroups.RemotePlayers;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool GetCharacterStruct<T>(uint playerId, out T s) where T : unmanaged, IEntityComponent
|
|
||||||
{
|
|
||||||
ExclusiveGroup[] characterGroups = CharacterExclusiveGroups.AllCharacters;
|
|
||||||
for (int i = 0; i < characterGroups.Length; i++)
|
|
||||||
{
|
|
||||||
EGID egid = new EGID(playerId, characterGroups[i]);
|
|
||||||
if (entitiesDB.Exists<T>(egid))
|
|
||||||
{
|
|
||||||
s = entitiesDB.QueryEntity<T>(egid);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool GetPlayerStruct<T>(uint playerId, out T s) where T : unmanaged, IEntityComponent
|
|
||||||
{
|
|
||||||
ExclusiveGroup[] playerGroups = PlayersExclusiveGroups.AllPlayers;
|
|
||||||
for (int i = 0; i < playerGroups.Length; i++)
|
|
||||||
{
|
|
||||||
EGID egid = new EGID(playerId, playerGroups[i]);
|
|
||||||
if (entitiesDB.Exists<T>(egid))
|
|
||||||
{
|
|
||||||
s = entitiesDB.QueryEntity<T>(egid);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EGID? GetThingLookedAt(uint playerId, 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,346 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
using HarmonyLib;
|
|
||||||
using IllusionInjector;
|
|
||||||
// test
|
|
||||||
using Svelto.ECS;
|
|
||||||
using RobocraftX.Blocks;
|
|
||||||
using RobocraftX.Common;
|
|
||||||
using RobocraftX.SimulationModeState;
|
|
||||||
using RobocraftX.FrontEnd;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Commands;
|
|
||||||
using GamecraftModdingAPI.Events;
|
|
||||||
using GamecraftModdingAPI.Utility;
|
|
||||||
using GamecraftModdingAPI.Blocks;
|
|
||||||
using GamecraftModdingAPI.Players;
|
|
||||||
|
|
||||||
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 Harmony 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();
|
|
||||||
Harmony.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();//(very) unstable
|
|
||||||
|
|
||||||
// debug/test handlers
|
|
||||||
HandlerBuilder.Builder()
|
|
||||||
.Name("appinit API debug")
|
|
||||||
.Handle(EventType.ApplicationInitialized)
|
|
||||||
.OnActivation(() => { Logging.Log("App Inited event!"); })
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
HandlerBuilder.Builder("menuact API debug")
|
|
||||||
.Handle(EventType.Menu)
|
|
||||||
.OnActivation(() => { Logging.Log("Menu Activated event!"); })
|
|
||||||
.OnDestruction(() => { Logging.Log("Menu Destroyed event!"); })
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
HandlerBuilder.Builder("menuswitch API debug")
|
|
||||||
.Handle(EventType.MenuSwitchedTo)
|
|
||||||
.OnActivation(() => { Logging.Log("Menu Switched To event!"); })
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
HandlerBuilder.Builder("gameact API debug")
|
|
||||||
.Handle(EventType.Menu)
|
|
||||||
.OnActivation(() => { Logging.Log("Game Activated event!"); })
|
|
||||||
.OnDestruction(() => { Logging.Log("Game Destroyed event!"); })
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
HandlerBuilder.Builder("gamerel API debug")
|
|
||||||
.Handle(EventType.GameReloaded)
|
|
||||||
.OnActivation(() => { Logging.Log("Game Reloaded event!"); })
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
HandlerBuilder.Builder("gameswitch API debug")
|
|
||||||
.Handle(EventType.GameSwitchedTo)
|
|
||||||
.OnActivation(() => { Logging.Log("Game Switched To event!"); })
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
HandlerBuilder.Builder("simulationswitch API debug")
|
|
||||||
.Handle(EventType.SimulationSwitchedTo)
|
|
||||||
.OnActivation(() => { Logging.Log("Game Mode Simulation Switched To event!"); })
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
HandlerBuilder.Builder("buildswitch API debug")
|
|
||||||
.Handle(EventType.BuildSwitchedTo)
|
|
||||||
.OnActivation(() => { Logging.Log("Game Mode Build Switched To event!"); })
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
HandlerBuilder.Builder("menu activated API error thrower test")
|
|
||||||
.Handle(EventType.Menu)
|
|
||||||
.OnActivation(() => { throw new Exception("Event Handler always throws an exception!"); })
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
// debug/test commands
|
|
||||||
if (Dependency.Hell("ExtraCommands"))
|
|
||||||
{
|
|
||||||
CommandBuilder.Builder()
|
|
||||||
.Name("Exit")
|
|
||||||
.Description("Close Gamecraft immediately, without any prompts")
|
|
||||||
.Action(() => { UnityEngine.Application.Quit(); })
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
CommandBuilder.Builder()
|
|
||||||
.Name("SetFOV")
|
|
||||||
.Description("Set the player camera's field of view")
|
|
||||||
.Action((float d) => { UnityEngine.Camera.main.fieldOfView = d; })
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
CommandBuilder.Builder()
|
|
||||||
.Name("MoveLastBlock")
|
|
||||||
.Description("Move the most-recently-placed block, and any connected blocks by the given offset")
|
|
||||||
.Action((float x, float y, float z) =>
|
|
||||||
{
|
|
||||||
if (GameState.IsBuildMode())
|
|
||||||
foreach (var block in Block.GetLastPlacedBlock().GetConnectedCubes())
|
|
||||||
block.Position += new Unity.Mathematics.float3(x, y, z);
|
|
||||||
else
|
|
||||||
GamecraftModdingAPI.Utility.Logging.CommandLogError("Blocks can only be moved in Build mode!");
|
|
||||||
}).Build();
|
|
||||||
|
|
||||||
CommandBuilder.Builder()
|
|
||||||
.Name("PlaceAluminium")
|
|
||||||
.Description("Place a block of aluminium at the given coordinates")
|
|
||||||
.Action((float x, float y, float z) =>
|
|
||||||
{
|
|
||||||
var block = Block.PlaceNew(BlockIDs.AluminiumCube, new float3(x, y, z));
|
|
||||||
Logging.CommandLog("Block placed with type: " + block.Type);
|
|
||||||
})
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
CommandBuilder.Builder()
|
|
||||||
.Name("PlaceAluminiumLots")
|
|
||||||
.Description("Place a lot of blocks of aluminium at the given coordinates")
|
|
||||||
.Action((float x, float y, float z) =>
|
|
||||||
{
|
|
||||||
Logging.CommandLog("Starting...");
|
|
||||||
var sw = Stopwatch.StartNew();
|
|
||||||
for (int i = 0; i < 100; i++)
|
|
||||||
for (int j = 0; j < 100; j++)
|
|
||||||
Block.PlaceNew(BlockIDs.AluminiumCube, new float3(x + i, y, z + j));
|
|
||||||
//Block.Sync();
|
|
||||||
sw.Stop();
|
|
||||||
Logging.CommandLog("Finished in " + sw.ElapsedMilliseconds + "ms");
|
|
||||||
})
|
|
||||||
.Build();
|
|
||||||
//With Sync(): 1135ms
|
|
||||||
//Without Sync(): 134ms
|
|
||||||
//Async: 348 794ms, doesn't freeze game
|
|
||||||
//Without Sync() but wait for submission: 530ms
|
|
||||||
//With Sync() at the end: 380ms
|
|
||||||
|
|
||||||
Block b = null;
|
|
||||||
CommandBuilder.Builder("moveBlockInSim", "Run in build mode first while looking at a block, then in sim to move it up")
|
|
||||||
.Action(() =>
|
|
||||||
{
|
|
||||||
if (b == null)
|
|
||||||
{
|
|
||||||
b = new Player(PlayerType.Local).GetBlockLookedAt();
|
|
||||||
Logging.CommandLog("Block saved: " + b);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Logging.CommandLog("Block moved to: " + (b.GetSimBody().Position += new float3(0, 2, 0)));
|
|
||||||
}).Build();
|
|
||||||
|
|
||||||
CommandBuilder.Builder("Error", "Throw an error to make sure SimpleCustomCommandEngine's wrapper catches it.")
|
|
||||||
.Action(() => { throw new Exception("Error Command always throws an error"); })
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
CommandBuilder.Builder("ColorBlock",
|
|
||||||
"Change color of the block looked at if there's any.")
|
|
||||||
.Action<string>(str =>
|
|
||||||
{
|
|
||||||
if (!Enum.TryParse(str, out BlockColors color))
|
|
||||||
{
|
|
||||||
Logging.CommandLog("Color " + str + " not found! Interpreting as 4 color values.");
|
|
||||||
var s = str.Split(' ');
|
|
||||||
new Player(PlayerType.Local).GetBlockLookedAt().CustomColor = new float4(float.Parse(s[0]),
|
|
||||||
float.Parse(s[1]), float.Parse(s[2]), float.Parse(s[3]));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
new Player(PlayerType.Local).GetBlockLookedAt().Color =
|
|
||||||
new BlockColor {Color = color};
|
|
||||||
Logging.CommandLog("Colored block to " + color);
|
|
||||||
|
|
||||||
}).Build();
|
|
||||||
|
|
||||||
CommandBuilder.Builder("GetBlockByID", "Gets a block based on its object identifier and teleports it up.")
|
|
||||||
.Action<char>(ch =>
|
|
||||||
{
|
|
||||||
foreach (var body in SimBody.GetFromObjectID(ch))
|
|
||||||
{
|
|
||||||
Logging.CommandLog("SimBody: " + body);
|
|
||||||
body.Position += new float3(0, 10, 0);
|
|
||||||
foreach (var bodyConnectedBody in body.GetConnectedBodies())
|
|
||||||
{
|
|
||||||
Logging.CommandLog("Moving " + bodyConnectedBody);
|
|
||||||
bodyConnectedBody.Position += new float3(0, 10, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).Build();
|
|
||||||
|
|
||||||
GameClient.SetDebugInfo("lookedAt", LookedAt);
|
|
||||||
GameClient.SetDebugInfo("InstalledMods", InstalledMods);
|
|
||||||
|
|
||||||
/*
|
|
||||||
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"));
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Player player;
|
|
||||||
|
|
||||||
private string LookedAt()
|
|
||||||
{
|
|
||||||
if (player == null)
|
|
||||||
player = new Player(PlayerType.Local);
|
|
||||||
if (GameState.IsBuildMode())
|
|
||||||
{
|
|
||||||
Block block = player.GetBlockLookedAt();
|
|
||||||
if (block == null) return "Block: none";
|
|
||||||
return "Block: " + block.Type + "\nColor: " + block.Color + "\n" + "At: " + block.Position
|
|
||||||
+ "\nText: " + block.Label;
|
|
||||||
}
|
|
||||||
if (GameState.IsSimulationMode())
|
|
||||||
{
|
|
||||||
SimBody body = player.GetSimBodyLookedAt();
|
|
||||||
if (body == null) return "Body: none";
|
|
||||||
return "Body: " + (body.Static ? "static" : "non-static")
|
|
||||||
+ "\nAt: " + body.Position + " - rotated: " + body.Rotation
|
|
||||||
+ "\nWith mass: " + body.Mass + " - center: " + body.CenterOfMass
|
|
||||||
+ "\nVelocity: " + body.Velocity + " - angular: " + body.AngularVelocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "Switching modes...";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string modsString;
|
|
||||||
private string InstalledMods()
|
|
||||||
{
|
|
||||||
if (modsString != null) return modsString;
|
|
||||||
StringBuilder sb = new StringBuilder("Installed mods:");
|
|
||||||
foreach (var plugin in PluginManager.Plugins)
|
|
||||||
sb.Append("\n" + plugin.Name + " - " + plugin.Version);
|
|
||||||
return modsString = sb.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnFixedUpdate() { }
|
|
||||||
|
|
||||||
public void OnLateUpdate() { }
|
|
||||||
|
|
||||||
public void OnLevelWasInitialized(int level) { }
|
|
||||||
|
|
||||||
public void OnLevelWasLoaded(int level) { }
|
|
||||||
|
|
||||||
public void OnUpdate() { }
|
|
||||||
|
|
||||||
[HarmonyPatch]
|
|
||||||
public class MinimumSpecsPatch
|
|
||||||
{
|
|
||||||
public static bool Prefix(ref bool __result)
|
|
||||||
{
|
|
||||||
__result = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MethodInfo TargetMethod()
|
|
||||||
{
|
|
||||||
return ((Func<bool>)MinimumSpecsCheck.CheckRequirementsMet).Method;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Utility
|
|
||||||
{
|
|
||||||
public static class AsyncUtils
|
|
||||||
{
|
|
||||||
private static AsyncUtilsEngine gameEngine = new AsyncUtilsEngine();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Waits for entity submission asynchronously.
|
|
||||||
/// </summary>
|
|
||||||
public static async Task WaitForSubmission()
|
|
||||||
{
|
|
||||||
await gameEngine.WaitForSubmission();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Setup(EnginesRoot enginesRoot)
|
|
||||||
{
|
|
||||||
gameEngine.Setup(enginesRoot.GenerateEntityFunctions(), enginesRoot.GenerateEntityFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Init()
|
|
||||||
{
|
|
||||||
GameEngineManager.AddGameEngine(gameEngine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
using System.Collections;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using RobocraftX.Schedulers;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Svelto.Tasks.ExtraLean;
|
|
||||||
|
|
||||||
using GamecraftModdingAPI.Engines;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Utility
|
|
||||||
{
|
|
||||||
public class AsyncUtilsEngine : IApiEngine
|
|
||||||
{
|
|
||||||
private IEntityFunctions _efu;
|
|
||||||
private IEntityFactory _efa;
|
|
||||||
private IEnumerator WaitForSubmissionInternal(IEntityFunctions efu, IEntityFactory efa,
|
|
||||||
EntitiesDB entitiesDB, TaskCompletionSource<object> task)
|
|
||||||
{
|
|
||||||
var waitEnumerator = new WaitForSubmissionEnumerator(efu, efa, entitiesDB);
|
|
||||||
while (waitEnumerator.MoveNext())
|
|
||||||
yield return null;
|
|
||||||
task.SetResult(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task WaitForSubmission()
|
|
||||||
{
|
|
||||||
var task = new TaskCompletionSource<object>();
|
|
||||||
WaitForSubmissionInternal(_efu, _efa, entitiesDB, task).RunOn(ExtraLean.EveryFrameStepRunner);
|
|
||||||
return task.Task;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Setup(IEntityFunctions efu, IEntityFactory efa)
|
|
||||||
{
|
|
||||||
_efu = efu;
|
|
||||||
_efa = efa;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Ready()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { get; set; }
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name { get; } = "GamecraftModdingAPIAsyncUtilsGameEngine";
|
|
||||||
public bool isRemovable { get; } = false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
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,25 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using RobocraftX.StateSync;
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
using HarmonyLib;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Utility
|
|
||||||
{
|
|
||||||
[HarmonyPatch(typeof(DeterministicStepCompositionRoot), "ResetWorld")]
|
|
||||||
public static class DeterministicStepCompositionRootPatch
|
|
||||||
{
|
|
||||||
private static SimpleEntitiesSubmissionScheduler engineRootScheduler;
|
|
||||||
public static void Postfix(SimpleEntitiesSubmissionScheduler scheduler)
|
|
||||||
{
|
|
||||||
engineRootScheduler = scheduler;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void SubmitEntitiesNow()
|
|
||||||
{
|
|
||||||
if (engineRootScheduler != null)
|
|
||||||
engineRootScheduler.SubmitEntities();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
using System;
|
|
||||||
using GamecraftModdingAPI.Blocks;
|
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Utility
|
|
||||||
{
|
|
||||||
public static class GameClient
|
|
||||||
{
|
|
||||||
private static DebugInterfaceEngine _engine = new DebugInterfaceEngine();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Saves the extra information to be displayed on the debug view.
|
|
||||||
/// The provided getter function is called each time the view updates so make sure it returns quickly.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">A global ID for the custom information</param>
|
|
||||||
/// <param name="contentGetter">A function that returns the current information</param>
|
|
||||||
public static void SetDebugInfo(string id, Func<string> contentGetter) => _engine.SetInfo(id, contentGetter);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes an information provided by a plugin.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The ID of the custom information</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static bool RemoveDebugInfo(string id) => _engine.RemoveInfo(id);
|
|
||||||
|
|
||||||
public static void Init()
|
|
||||||
{
|
|
||||||
GameEngineManager.AddGameEngine(_engine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,112 +0,0 @@
|
||||||
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()
|
|
||||||
{
|
|
||||||
if (!SerializerManager.ExistsSerializer(typeof(ModVersionStruct).FullName))
|
|
||||||
{
|
|
||||||
SerializerManager.AddSerializer<ModVersionDescriptor>(new SimpleEntitySerializer<ModVersionDescriptor>(
|
|
||||||
(_) => { return new EGID[1] { new EGID(0u, ApiExclusiveGroups.versionGroup) }; }
|
|
||||||
));
|
|
||||||
}
|
|
||||||
EventManager.AddEventEmitter(versionEngine);
|
|
||||||
isEnabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Disable API version tracking.
|
|
||||||
/// </summary>
|
|
||||||
public static void Disable()
|
|
||||||
{
|
|
||||||
EventManager.AddEventEmitter(versionEngine);
|
|
||||||
isEnabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Init() { }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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>())),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
1574
MakeEverythingPublicInGame/MakeEverythingPublicInGame.csproj
Normal file
1574
MakeEverythingPublicInGame/MakeEverythingPublicInGame.csproj
Normal file
File diff suppressed because it is too large
Load diff
25
MakeEverythingPublicInGame/Program.cs
Normal file
25
MakeEverythingPublicInGame/Program.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
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,24 +1,31 @@
|
||||||
# GamecraftModdingAPI
|
# TechbloxModdingAPI
|
||||||
|
|
||||||
Unofficial Gamecraft modding API for interfacing Gamecraft from mods.
|
Unofficial Techblox modding API for interfacing Techblox from mods.
|
||||||
|
|
||||||
The GamecraftModdingAPI aims to simplify the mods in two ways:
|
The TechbloxModdingAPI 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 GamecraftModdingAPI or Gamecraft updates.
|
This means your code won't break when the TechbloxModdingAPI or Techblox 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.gg/xjnFxQV).
|
For more support, join the ExMods [Discord](https://discord.exmods.org).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
[Please follow the official mod installation guide](https://www.exmods.org/guides/install.html)
|
[Please follow the official mod installation guide](https://www.exmods.org/guides/install.html) or use GCMM.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
To get started, create a symbolic link called `ref` in the root of the project, or one folder higher, linking to the 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
|
||||||
GamecraftModdingAPI includes [Harmony](https://github.com/pardeike/Harmony) to modify the behaviour of existing Gamecraft code.
|
TechbloxModdingAPI includes [Harmony](https://github.com/pardeike/Harmony) to modify the behaviour of existing Techblox code.
|
||||||
|
|
||||||
# Disclaimer
|
# Disclaimer
|
||||||
This API is an unofficial modification of Gamecraft software, and is not endorsed or supported by FreeJam or Gamecraft.
|
This API is an unofficial modification of Techblox software, and is not endorsed or supported by FreeJam or Techblox.
|
||||||
The GamecraftModdingAPI developer(s) claim no rights on the Gamecraft code referenced within this project.
|
The TechbloxModdingAPI developer(s) claim no rights on the Techblox 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).
|
||||||
|
|
||||||
|
|
44
TechbloxModdingAPI.sln
Normal file
44
TechbloxModdingAPI.sln
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
|
||||||
|
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
|
58
TechbloxModdingAPI/App/AntiAntiCheatPatch.cs
Normal file
58
TechbloxModdingAPI/App/AntiAntiCheatPatch.cs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
TechbloxModdingAPI/App/AppCallbacksTest.cs
Normal file
35
TechbloxModdingAPI/App/AppCallbacksTest.cs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
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
|
||||||
|
}
|
42
TechbloxModdingAPI/App/AppExceptions.cs
Normal file
42
TechbloxModdingAPI/App/AppExceptions.cs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
171
TechbloxModdingAPI/App/Client.cs
Normal file
171
TechbloxModdingAPI/App/Client.cs
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
TechbloxModdingAPI/App/ClientAlertTest.cs
Normal file
67
TechbloxModdingAPI/App/ClientAlertTest.cs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
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
|
||||||
|
}
|
27
TechbloxModdingAPI/App/CurrentGameMode.cs
Normal file
27
TechbloxModdingAPI/App/CurrentGameMode.cs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
490
TechbloxModdingAPI/App/Game.cs
Normal file
490
TechbloxModdingAPI/App/Game.cs
Normal file
|
@ -0,0 +1,490 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
TechbloxModdingAPI/App/GameBuildSimEventEngine.cs
Normal file
47
TechbloxModdingAPI/App/GameBuildSimEventEngine.cs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
195
TechbloxModdingAPI/App/GameGameEngine.cs
Normal file
195
TechbloxModdingAPI/App/GameGameEngine.cs
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
197
TechbloxModdingAPI/App/GameMenuEngine.cs
Normal file
197
TechbloxModdingAPI/App/GameMenuEngine.cs
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
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
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
27
TechbloxModdingAPI/App/UserPrompts.cs
Normal file
27
TechbloxModdingAPI/App/UserPrompts.cs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
using System;
|
||||||
|
using HarmonyLib;
|
||||||
|
|
||||||
|
using RobocraftX.Services;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.App
|
||||||
|
{
|
||||||
|
public class DualChoicePrompt : MultiChoiceError
|
||||||
|
{
|
||||||
|
public DualChoicePrompt(string errorMessage, string title, string firstButtonText, Action firstButtonAction, string secondButtonText, Action secondButtonAction) : base(errorMessage, firstButtonText, firstButtonAction, secondButtonText, secondButtonAction)
|
||||||
|
{
|
||||||
|
// internal readonly field smh
|
||||||
|
new Traverse(this).Field<string>("Title").Value = title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SingleChoicePrompt : SingleChoiceError
|
||||||
|
{
|
||||||
|
public SingleChoicePrompt(string errorMessage, string buttonText, Action buttonClickAction) : base(errorMessage, buttonText, buttonClickAction)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public SingleChoicePrompt(string titleText, string errorMessage, string buttonText, Action buttonClickAction) : base(titleText, errorMessage, buttonText, buttonClickAction)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
519
TechbloxModdingAPI/Block.cs
Normal file
519
TechbloxModdingAPI/Block.cs
Normal file
|
@ -0,0 +1,519 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using DataLoader;
|
||||||
|
using Gamecraft.Blocks.BlockGroups;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Svelto.ECS.EntityStructs;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.Blocks;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
using HarmonyLib;
|
||||||
|
using RobocraftX.PilotSeat;
|
||||||
|
using RobocraftX.Rendering;
|
||||||
|
using Techblox.BlockLabelsServer;
|
||||||
|
using TechbloxModdingAPI.Blocks;
|
||||||
|
using TechbloxModdingAPI.Blocks.Engines;
|
||||||
|
using TechbloxModdingAPI.Tests;
|
||||||
|
using TechbloxModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A single (perhaps scaled) block. Properties may return default values if the block is removed and then setting them is ignored.
|
||||||
|
/// For specific block type operations, use the specialised block classes in the TechbloxModdingAPI.Blocks namespace.
|
||||||
|
/// </summary>
|
||||||
|
public class Block : EcsObjectBase, IEquatable<Block>, IEquatable<EGID>
|
||||||
|
{
|
||||||
|
protected static readonly PlacementEngine PlacementEngine = new PlacementEngine();
|
||||||
|
protected static readonly MovementEngine MovementEngine = new MovementEngine();
|
||||||
|
protected static readonly RotationEngine RotationEngine = new RotationEngine();
|
||||||
|
protected static readonly RemovalEngine RemovalEngine = new RemovalEngine();
|
||||||
|
protected static readonly SignalEngine SignalEngine = new SignalEngine();
|
||||||
|
protected static readonly BlockEventsEngine BlockEventsEngine = new BlockEventsEngine();
|
||||||
|
protected static readonly ScalingEngine ScalingEngine = new ScalingEngine();
|
||||||
|
protected static readonly BlockCloneEngine BlockCloneEngine = new BlockCloneEngine();
|
||||||
|
|
||||||
|
protected internal static readonly BlockEngine BlockEngine = new BlockEngine();
|
||||||
|
|
||||||
|
/// <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="position">The block's position - default block size is 0.2</param>
|
||||||
|
/// <param name="autoWire">Whether the block should be auto-wired (if functional)</param>
|
||||||
|
/// <param name="player">The player who placed the block</param>
|
||||||
|
/// <returns>The placed block or null if failed</returns>
|
||||||
|
public static Block PlaceNew(BlockIDs block, float3 position, bool autoWire = false, Player player = null)
|
||||||
|
{
|
||||||
|
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
|
||||||
|
{
|
||||||
|
var initializer = PlacementEngine.PlaceBlock(block, position, player, autoWire);
|
||||||
|
var egid = initializer.EGID;
|
||||||
|
var bl = New(egid);
|
||||||
|
bl.InitData = initializer;
|
||||||
|
Placed += bl.OnPlacedInit;
|
||||||
|
return bl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the most recently placed block.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The block object or null if doesn't exist</returns>
|
||||||
|
public static Block GetLastPlacedBlock()
|
||||||
|
{
|
||||||
|
uint lastBlockID = CommonExclusiveGroups.blockIDGeneratorClient.Peek() - 1;
|
||||||
|
EGID? egid = BlockEngine.FindBlockEGID(lastBlockID);
|
||||||
|
return egid.HasValue ? New(egid.Value) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*public static Block CreateGhostBlock()
|
||||||
|
{
|
||||||
|
return BlockGroup._engine.BuildGhostChild();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An event that fires each time a block is placed.
|
||||||
|
/// </summary>
|
||||||
|
public static event EventHandler<BlockPlacedRemovedEventArgs> Placed
|
||||||
|
{ //TODO: Rename and add instance version in 3.0
|
||||||
|
add => BlockEventsEngine.Placed += value;
|
||||||
|
remove => BlockEventsEngine.Placed -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An event that fires each time a block is removed.
|
||||||
|
/// </summary>
|
||||||
|
public static event EventHandler<BlockPlacedRemovedEventArgs> Removed
|
||||||
|
{
|
||||||
|
add => BlockEventsEngine.Removed += value;
|
||||||
|
remove => BlockEventsEngine.Removed -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly Dictionary<ExclusiveBuildGroup, (Func<EGID, Block> Constructor, Type Type)> GroupToConstructor =
|
||||||
|
new Dictionary<ExclusiveBuildGroup, (Func<EGID, Block>, Type)>
|
||||||
|
{
|
||||||
|
{CommonExclusiveGroups.DAMPEDSPRING_BLOCK_GROUP, (id => new DampedSpring(id), typeof(DampedSpring))},
|
||||||
|
{CommonExclusiveGroups.ENGINE_BLOCK_BUILD_GROUP, (id => new Engine(id), typeof(Engine))},
|
||||||
|
{CommonExclusiveGroups.LOGIC_BLOCK_GROUP, (id => new LogicGate(id), typeof(LogicGate))},
|
||||||
|
{CommonExclusiveGroups.PISTON_BLOCK_GROUP, (id => new Piston(id), typeof(Piston))},
|
||||||
|
{CommonExclusiveGroups.SERVO_BLOCK_GROUP, (id => new Servo(id), typeof(Servo))},
|
||||||
|
{CommonExclusiveGroups.WHEELRIG_BLOCK_BUILD_GROUP, (id => new WheelRig(id), typeof(WheelRig))}
|
||||||
|
};
|
||||||
|
|
||||||
|
static Block()
|
||||||
|
{
|
||||||
|
foreach (var group in SeatGroups.SEATS_BLOCK_GROUPS) // Adds driver and passenger seats, occupied and unoccupied
|
||||||
|
GroupToConstructor.Add(group, (id => new Seat(id), typeof(Seat)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a correctly typed instance of this block. The instances are shared for a specific block.
|
||||||
|
/// If an instance is no longer referenced a new instance is returned.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="egid">The EGID of the block</param>
|
||||||
|
/// <param name="signaling">Whether the block is definitely a signaling block</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
internal static Block New(EGID egid, bool signaling = false)
|
||||||
|
{
|
||||||
|
if (egid == default) return null;
|
||||||
|
if (GroupToConstructor.ContainsKey(egid.groupID))
|
||||||
|
{
|
||||||
|
var (constructor, type) = GroupToConstructor[egid.groupID];
|
||||||
|
return GetInstance(egid, constructor, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return signaling
|
||||||
|
? GetInstance(egid, e => new SignalingBlock(e))
|
||||||
|
: GetInstance(egid, e => new Block(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Block(EGID id) : base(id)
|
||||||
|
{
|
||||||
|
Type expectedType;
|
||||||
|
if (GroupToConstructor.ContainsKey(id.groupID) &&
|
||||||
|
!GetType().IsAssignableFrom(expectedType = GroupToConstructor[id.groupID].Type))
|
||||||
|
throw new BlockSpecializationException($"Incorrect block type! Expected: {expectedType} Actual: {GetType()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This overload searches for the correct group the block is in.
|
||||||
|
/// It will throw an exception if the block doesn't exist.
|
||||||
|
/// Use the EGID constructor where possible or subclasses of Block as those specify the group.
|
||||||
|
/// </summary>
|
||||||
|
public Block(uint id) : this(BlockEngine.FindBlockEGID(id)
|
||||||
|
?? throw new BlockTypeException(
|
||||||
|
"Could not find the appropriate group for the block." +
|
||||||
|
" The block probably doesn't exist or hasn't been submitted."))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Places a new block in the world.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The block's type</param>
|
||||||
|
/// <param name="position">The block's position (a block is 0.2 wide in terms of position)</param>
|
||||||
|
/// <param name="autoWire">Whether the block should be auto-wired (if functional)</param>
|
||||||
|
/// <param name="player">The player who placed the block</param>
|
||||||
|
public Block(BlockIDs type, float3 position, bool autoWire = false, Player player = null)
|
||||||
|
: base(block =>
|
||||||
|
{
|
||||||
|
if (!PlacementEngine.IsInGame || !GameState.IsBuildMode())
|
||||||
|
throw new BlockException("Blocks can only be placed in build mode.");
|
||||||
|
var initializer = PlacementEngine.PlaceBlock(type, position, player, autoWire);
|
||||||
|
block.InitData = initializer;
|
||||||
|
Placed += ((Block)block).OnPlacedInit;
|
||||||
|
return initializer.EGID;
|
||||||
|
})
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private EGID copiedFrom;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The block's current position or zero if the block no longer exists.
|
||||||
|
/// A block is 0.2 wide by default in terms of position.
|
||||||
|
/// </summary>
|
||||||
|
public float3 Position
|
||||||
|
{
|
||||||
|
get => MovementEngine.GetPosition(this);
|
||||||
|
set
|
||||||
|
{
|
||||||
|
MovementEngine.MoveBlock(this, value);
|
||||||
|
if (blockGroup != null)
|
||||||
|
blockGroup.PosAndRotCalculated = false;
|
||||||
|
BlockEngine.UpdateDisplayedBlock(Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The block's current rotation in degrees or zero if the block doesn't exist.
|
||||||
|
/// </summary>
|
||||||
|
public float3 Rotation
|
||||||
|
{
|
||||||
|
get => RotationEngine.GetRotation(this);
|
||||||
|
set
|
||||||
|
{
|
||||||
|
RotationEngine.RotateBlock(this, value);
|
||||||
|
if (blockGroup != null)
|
||||||
|
blockGroup.PosAndRotCalculated = false;
|
||||||
|
BlockEngine.UpdateDisplayedBlock(Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The block's non-uniform scale or zero if the block's invalid. Independent of the uniform scaling.
|
||||||
|
/// The default scale of 1 means 0.2 in terms of position.
|
||||||
|
/// </summary>
|
||||||
|
public float3 Scale
|
||||||
|
{
|
||||||
|
get => BlockEngine.GetBlockInfo<ScalingEntityStruct>(this).scale;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
int uscale = UniformScale;
|
||||||
|
if (value.x < 4e-5) value.x = uscale;
|
||||||
|
if (value.y < 4e-5) value.y = uscale;
|
||||||
|
if (value.z < 4e-5) value.z = uscale;
|
||||||
|
BlockEngine.GetBlockInfo<ScalingEntityStruct>(this).scale = value;
|
||||||
|
//BlockEngine.GetBlockInfo<GridScaleStruct>(this).gridScale = value - (int3) value + 1;
|
||||||
|
if (!Exists) return; //UpdateCollision needs the block to exist
|
||||||
|
ScalingEngine.UpdateCollision(Id);
|
||||||
|
BlockEngine.UpdateDisplayedBlock(Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The block's uniform scale or zero if the block's invalid. Also sets the non-uniform scale.
|
||||||
|
/// The default scale of 1 means 0.2 in terms of position.
|
||||||
|
/// </summary>
|
||||||
|
public int UniformScale
|
||||||
|
{
|
||||||
|
get => BlockEngine.GetBlockInfo<UniformBlockScaleEntityStruct>(this).scaleFactor;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value < 1) value = 1;
|
||||||
|
BlockEngine.GetBlockInfo<UniformBlockScaleEntityStruct>(this).scaleFactor = value;
|
||||||
|
Scale = new float3(value, value, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the block is flipped.
|
||||||
|
*/
|
||||||
|
public bool Flipped
|
||||||
|
{
|
||||||
|
get => BlockEngine.GetBlockInfo<ScalingEntityStruct>(this).scale.x < 0;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ref var st = ref BlockEngine.GetBlockInfo<ScalingEntityStruct>(this);
|
||||||
|
st.scale.x = math.abs(st.scale.x) * (value ? -1 : 1);
|
||||||
|
BlockEngine.UpdatePrefab(this, (byte) Material, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The block's type (ID). Returns BlockIDs.Invalid if the block doesn't exist anymore.
|
||||||
|
/// </summary>
|
||||||
|
public BlockIDs Type
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var opt = BlockEngine.GetBlockInfoOptional<DBEntityStruct>(this);
|
||||||
|
return opt ? (BlockIDs) opt.Get().DBID : BlockIDs.Invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The block's color. Returns BlockColors.Default if the block no longer exists.
|
||||||
|
/// </summary>
|
||||||
|
public BlockColor Color
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var opt = BlockEngine.GetBlockInfoOptional<ColourParameterEntityStruct>(this);
|
||||||
|
return new BlockColor(opt ? opt.Get().indexInPalette : byte.MaxValue);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value.Color == BlockColors.Default)
|
||||||
|
value = new BlockColor(FullGameFields._dataDb.TryGetValue((int) Type, out CubeListData cld)
|
||||||
|
? cld.DefaultColour
|
||||||
|
: throw new BlockTypeException("Unknown block type! Could not set default color."));
|
||||||
|
ref var color = ref BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(this);
|
||||||
|
color.indexInPalette = value.Index;
|
||||||
|
color.hasNetworkChange = true;
|
||||||
|
color.paletteColour = BlockEngine.ConvertBlockColor(color.indexInPalette); //Setting to 255 results in black
|
||||||
|
BlockEngine.UpdateBlockColor(Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The block's exact color. Gets reset to the palette color (Color property) after reentering the game.
|
||||||
|
/// </summary>
|
||||||
|
public float4 CustomColor
|
||||||
|
{
|
||||||
|
get => BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(this).paletteColour;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ref var color = ref BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(this);
|
||||||
|
color.paletteColour = value;
|
||||||
|
color.hasNetworkChange = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The block's material.
|
||||||
|
*/
|
||||||
|
public BlockMaterial Material
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var opt = BlockEngine.GetBlockInfoOptional<CubeMaterialStruct>(this);
|
||||||
|
return opt ? (BlockMaterial) opt.Get().materialId : BlockMaterial.Default;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
byte val = (byte) value;
|
||||||
|
if (value == BlockMaterial.Default)
|
||||||
|
val = FullGameFields._dataDb.TryGetValue((int) Type, out CubeListData cld)
|
||||||
|
? cld.DefaultMaterialID
|
||||||
|
: throw new BlockTypeException("Unknown block type! Could not set default material.");
|
||||||
|
if (!FullGameFields._dataDb.ContainsKey<MaterialPropertiesData>(val))
|
||||||
|
throw new BlockException($"Block material {value} does not exist!");
|
||||||
|
ref var comp = ref BlockEngine.GetBlockInfo<CubeMaterialStruct>(this);
|
||||||
|
if (comp.materialId == val)
|
||||||
|
return;
|
||||||
|
comp.materialId = val;
|
||||||
|
BlockEngine.UpdatePrefab(this, val, Flipped); //The default causes the screen to go black
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The text displayed on the block if applicable, or null.
|
||||||
|
/// Setting it is temporary to the session, it won't be saved.
|
||||||
|
/// </summary>
|
||||||
|
[TestValue(null)]
|
||||||
|
public string Label
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var opt = BlockEngine.GetBlockInfoOptional<LabelResourceIDComponent>(this);
|
||||||
|
return opt ? FullGameFields._managers.blockLabelResourceManager.GetText(opt.Get().instanceID) : null;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var opt = BlockEngine.GetBlockInfoOptional<LabelResourceIDComponent>(this);
|
||||||
|
if (opt) FullGameFields._managers.blockLabelResourceManager.SetText(opt.Get().instanceID, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockGroup blockGroup;
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the block group this block is a part of. Block groups can also be placed using blueprints.
|
||||||
|
/// Returns null if not part of a group, although all blocks should have their own by default.<br />
|
||||||
|
/// Setting the group after the block has been initialized will not update everything properly,
|
||||||
|
/// so you can only set this property on blocks newly placed by your code.<br />
|
||||||
|
/// To set it for existing blocks, you can use the Copy() method and set the property on the resulting block
|
||||||
|
/// (and remove this block).
|
||||||
|
/// </summary>
|
||||||
|
public BlockGroup BlockGroup
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (blockGroup != null) return blockGroup;
|
||||||
|
if (!GameState.IsBuildMode()) return null; // Breaks in simulation
|
||||||
|
var bgec = BlockEngine.GetBlockInfo<BlockGroupEntityComponent>(this);
|
||||||
|
return blockGroup = bgec.currentBlockGroup == -1
|
||||||
|
? null
|
||||||
|
: GetInstance(new EGID((uint)bgec.currentBlockGroup, BlockGroupExclusiveGroups.BlockGroupEntityGroup),
|
||||||
|
egid => new BlockGroup((int)egid.entityID, this));
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (Exists)
|
||||||
|
{
|
||||||
|
Logging.LogWarning("Attempted to set group of existing block. This is not supported."
|
||||||
|
+ " Copy the block and set the group of the resulting block.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
blockGroup?.RemoveInternal(this);
|
||||||
|
if (!InitData.Valid)
|
||||||
|
return;
|
||||||
|
BlockEngine.GetBlockInfo<BlockGroupEntityComponent>(this).currentBlockGroup = (int?) value?.Id.entityID ?? -1;
|
||||||
|
value?.AddInternal(this);
|
||||||
|
blockGroup = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the block should be static in simulation. If set, it cannot be moved. The effect is temporary, it will not be saved with the block.
|
||||||
|
/// </summary>
|
||||||
|
public bool Static
|
||||||
|
{
|
||||||
|
get => BlockEngine.GetBlockInfo<BlockStaticComponent>(this).isStatic;
|
||||||
|
set => BlockEngine.GetBlockInfo<BlockStaticComponent>(this).isStatic = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The mass of the block.
|
||||||
|
/// </summary>
|
||||||
|
public float Mass
|
||||||
|
{
|
||||||
|
get => BlockEngine.GetBlockInfo<MassStruct>(this).mass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Block complexity used for build rules. Determines the 'cost' of the block.
|
||||||
|
/// </summary>
|
||||||
|
public BlockComplexity Complexity
|
||||||
|
{
|
||||||
|
get => new(BlockEngine.GetBlockInfo<BlockComplexityComponent>(this));
|
||||||
|
set => BlockEngine.GetBlockInfo<BlockComplexityComponent>(this) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the block exists. The other properties will return a default value if the block doesn't exist.
|
||||||
|
/// If the block was just placed, then this will also return false but the properties will work correctly.
|
||||||
|
/// </summary>
|
||||||
|
public bool Exists => BlockEngine.BlockExists(Id);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an array of blocks that are connected to this one. Returns an empty array if the block doesn't exist.
|
||||||
|
/// </summary>
|
||||||
|
public Block[] GetConnectedCubes() => BlockEngine.GetConnectedBlocks(Id);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes this block.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the block exists and could be removed.</returns>
|
||||||
|
public bool Remove() => RemovalEngine.RemoveBlock(Id);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the rigid body of the chunk of blocks this one belongs to during simulation.
|
||||||
|
/// Can be used to apply forces or move the block around while the simulation is running.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The SimBody of the chunk or null if the block doesn't exist or not in simulation mode.</returns>
|
||||||
|
public SimBody GetSimBody()
|
||||||
|
{
|
||||||
|
var st = BlockEngine.GetBlockInfo<GridConnectionsEntityStruct>(this);
|
||||||
|
/*return st.machineRigidBodyId != uint.MaxValue
|
||||||
|
? new SimBody(st.machineRigidBodyId, st.clusterId) - TODO:
|
||||||
|
: null;*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a copy of the block in the game with the same properties, stats and wires.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Block Copy()
|
||||||
|
{
|
||||||
|
var block = PlaceNew(Type, Position);
|
||||||
|
block.Rotation = Rotation;
|
||||||
|
block.Color = Color;
|
||||||
|
block.Material = Material;
|
||||||
|
block.UniformScale = UniformScale;
|
||||||
|
block.Scale = Scale;
|
||||||
|
block.copiedFrom = Id;
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPlacedInit(object sender, BlockPlacedRemovedEventArgs e)
|
||||||
|
{ //Member method instead of lambda to avoid constantly creating delegates
|
||||||
|
if (e.ID != Id) return;
|
||||||
|
Placed -= OnPlacedInit; //And we can reference it
|
||||||
|
InitData = default; //Remove initializer as it's no longer valid - if the block gets removed it shouldn't be used again
|
||||||
|
if (copiedFrom != default)
|
||||||
|
BlockCloneEngine.CopyBlockStats(copiedFrom, Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{nameof(Id)}: {Id}, {nameof(Position)}: {Position}, {nameof(Type)}: {Type}, {nameof(Color)}: {Color}, {nameof(Exists)}: {Exists}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(Block other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, other)) return false;
|
||||||
|
if (ReferenceEquals(this, other)) return true;
|
||||||
|
return Id.Equals(other.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(EGID other)
|
||||||
|
{
|
||||||
|
return Id.Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj)) return false;
|
||||||
|
if (ReferenceEquals(this, obj)) return true;
|
||||||
|
if (obj.GetType() != this.GetType()) return false;
|
||||||
|
return Equals((Block) obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return Id.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
GameEngineManager.AddGameEngine(PlacementEngine);
|
||||||
|
GameEngineManager.AddGameEngine(MovementEngine);
|
||||||
|
GameEngineManager.AddGameEngine(RotationEngine);
|
||||||
|
GameEngineManager.AddGameEngine(RemovalEngine);
|
||||||
|
GameEngineManager.AddGameEngine(BlockEngine);
|
||||||
|
GameEngineManager.AddGameEngine(BlockEventsEngine);
|
||||||
|
GameEngineManager.AddGameEngine(ScalingEngine);
|
||||||
|
GameEngineManager.AddGameEngine(SignalEngine);
|
||||||
|
GameEngineManager.AddGameEngine(BlockCloneEngine);
|
||||||
|
Wire.signalEngine = SignalEngine; // requires same functionality, no need to duplicate the engine
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
217
TechbloxModdingAPI/BlockGroup.cs
Normal file
217
TechbloxModdingAPI/BlockGroup.cs
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Gamecraft.Blocks.BlockGroups;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
using TechbloxModdingAPI.Blocks;
|
||||||
|
using TechbloxModdingAPI.Blocks.Engines;
|
||||||
|
using TechbloxModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A group of blocks that can be selected together. The placed version of blueprints. Dispose after usage.
|
||||||
|
/// </summary>
|
||||||
|
public class BlockGroup : EcsObjectBase, ICollection<Block>, IDisposable
|
||||||
|
{
|
||||||
|
internal static BlueprintEngine _engine = new BlueprintEngine();
|
||||||
|
private readonly Block sourceBlock;
|
||||||
|
private readonly List<Block> blocks;
|
||||||
|
private float3 position, rotation;
|
||||||
|
internal bool PosAndRotCalculated;
|
||||||
|
|
||||||
|
internal BlockGroup(int id, Block block) : base(new EGID((uint)id,
|
||||||
|
BlockGroupExclusiveGroups.BlockGroupEntityGroup))
|
||||||
|
{
|
||||||
|
if (id == BlockGroupUtility.GROUP_UNASSIGNED)
|
||||||
|
throw new BlockException("Cannot create a block group for blocks without a group!");
|
||||||
|
sourceBlock = block;
|
||||||
|
blocks = new List<Block>(GetBlocks());
|
||||||
|
Block.Removed += OnBlockRemoved;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBlockRemoved(object sender, BlockPlacedRemovedEventArgs e)
|
||||||
|
{
|
||||||
|
//blocks.RemoveAll(block => block.Id == e.ID); - Allocation heavy
|
||||||
|
int index = -1;
|
||||||
|
for (int i = 0; i < blocks.Count; i++)
|
||||||
|
{
|
||||||
|
if (blocks[i].Id == e.ID)
|
||||||
|
{
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index != -1) blocks.RemoveAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Block.Removed -= OnBlockRemoved;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The position of the block group (center). Can only be used after initialization is complete.
|
||||||
|
/// </summary>
|
||||||
|
public float3 Position
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!PosAndRotCalculated)
|
||||||
|
Refresh();
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var diff = value - position;
|
||||||
|
foreach (var block in blocks)
|
||||||
|
block.Position += diff;
|
||||||
|
if (!PosAndRotCalculated) //The condition can only be true if a block has been added/removed manually
|
||||||
|
Refresh(); //So the blocks array is up to date
|
||||||
|
else
|
||||||
|
position += diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The rotation of the block group. Can only be used after initialization is complete.
|
||||||
|
/// </summary>
|
||||||
|
public float3 Rotation
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!PosAndRotCalculated)
|
||||||
|
Refresh();
|
||||||
|
return rotation;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var diff = value - rotation;
|
||||||
|
var qdiff = Quaternion.Euler(diff);
|
||||||
|
foreach (var block in blocks)
|
||||||
|
{
|
||||||
|
block.Rotation += diff;
|
||||||
|
block.Position = qdiff * block.Position;
|
||||||
|
}
|
||||||
|
if (!PosAndRotCalculated)
|
||||||
|
Refresh();
|
||||||
|
else
|
||||||
|
rotation += diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*/// <summary>
|
||||||
|
/// Removes all of the blocks in this group from the world.
|
||||||
|
/// </summary>
|
||||||
|
public void RemoveBlocks()
|
||||||
|
{
|
||||||
|
_engine.RemoveBlockGroup(Id); - TODO: Causes a hard crash
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new block group consisting of a single block.
|
||||||
|
/// You can add more blocks using the Add() method or by setting the BlockGroup property of the blocks.<br />
|
||||||
|
/// Note that only newly placed blocks can be added to groups.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="block">The block to add</param>
|
||||||
|
/// <returns>A new block group containing the given block</returns>
|
||||||
|
public static BlockGroup Create(Block block)
|
||||||
|
{
|
||||||
|
var bg = new BlockGroup(_engine.CreateBlockGroup(block.Position, Quaternion.Euler(block.Rotation)), block);
|
||||||
|
block.BlockGroup = bg;
|
||||||
|
return bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Collects each block that is a part of this group. Also sets the position and rotation.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An array of blocks</returns>
|
||||||
|
private Block[] GetBlocks()
|
||||||
|
{
|
||||||
|
if (!sourceBlock.Exists) return new[] {sourceBlock}; //The block must exist to get the others
|
||||||
|
var ret = _engine.GetBlocksFromGroup(sourceBlock.Id, out var pos, out var rot);
|
||||||
|
position = pos;
|
||||||
|
rotation = ((Quaternion) rot).eulerAngles;
|
||||||
|
PosAndRotCalculated = true;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Refresh()
|
||||||
|
{
|
||||||
|
blocks.Clear();
|
||||||
|
blocks.AddRange(GetBlocks());
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Init()
|
||||||
|
{
|
||||||
|
GameEngineManager.AddGameEngine(_engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<Block> GetEnumerator() => blocks.GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => blocks.GetEnumerator();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a block to the group. You can only add newly placed blocks
|
||||||
|
/// so that the game initializes the group membership properly.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item"></param>
|
||||||
|
/// <exception cref="NullReferenceException"></exception>
|
||||||
|
public void Add(Block item)
|
||||||
|
{
|
||||||
|
if (item == null) throw new NullReferenceException("Cannot add null to a block group");
|
||||||
|
item.BlockGroup = this; //Calls AddInternal
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void AddInternal(Block item)
|
||||||
|
{
|
||||||
|
blocks.Add(item);
|
||||||
|
_engine.AddBlockToGroup(item.Id, (int) Id.entityID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes all blocks from this group.
|
||||||
|
/// You cannot remove blocks that have been initialized, only those that you placed recently.
|
||||||
|
/// </summary>
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
while (blocks.Count > 0)
|
||||||
|
Remove(blocks[blocks.Count - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(Block item) => blocks.Contains(item);
|
||||||
|
public void CopyTo(Block[] array, int arrayIndex) => blocks.CopyTo(array, arrayIndex);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a block from this group.
|
||||||
|
/// You cannot remove blocks that have been initialized, only those that you placed recently.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="NullReferenceException"></exception>
|
||||||
|
public bool Remove(Block item)
|
||||||
|
{
|
||||||
|
if (item == null) throw new NullReferenceException("Cannot remove null from a block group");
|
||||||
|
bool ret = item.BlockGroup == this;
|
||||||
|
if (ret)
|
||||||
|
item.BlockGroup = null; //Calls RemoveInternal
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void RemoveInternal(Block item) => blocks.Remove(item);
|
||||||
|
|
||||||
|
public int Count => blocks.Count;
|
||||||
|
public bool IsReadOnly { get; } = false;
|
||||||
|
|
||||||
|
public Block this[int index] => blocks[index]; //Setting is not supported, since the order doesn't matter
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{nameof(Id)}: {Id}, {nameof(Position)}: {Position}, {nameof(Rotation)}: {Rotation}, {nameof(Count)}: {Count}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
64
TechbloxModdingAPI/Blocks/BlockColor.cs
Normal file
64
TechbloxModdingAPI/Blocks/BlockColor.cs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
using System;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
public struct BlockColor
|
||||||
|
{
|
||||||
|
public BlockColors Color => Index == byte.MaxValue
|
||||||
|
? BlockColors.Default
|
||||||
|
: (BlockColors) (Index % 10);
|
||||||
|
|
||||||
|
public byte Darkness => (byte) (Index == byte.MaxValue
|
||||||
|
? 0
|
||||||
|
: Index / 10);
|
||||||
|
|
||||||
|
public byte Index { get; }
|
||||||
|
|
||||||
|
public BlockColor(byte index)
|
||||||
|
{
|
||||||
|
if (index > 99 && index != byte.MaxValue)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(index), "Invalid color index. Must be 0-90 or 255.");
|
||||||
|
Index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockColor(BlockColors color, byte darkness = 0)
|
||||||
|
{
|
||||||
|
if (darkness > 9)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(darkness), "Darkness must be 0-9 where 0 is default.");
|
||||||
|
if (color > BlockColors.Red && color != BlockColors.Default) //Last valid color
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(color), "Invalid color!");
|
||||||
|
Index = (byte) (darkness * 10 + (byte) color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator BlockColor(BlockColors color)
|
||||||
|
{
|
||||||
|
return new BlockColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float4 RGBA => Block.BlockEngine.ConvertBlockColor(Index);
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{nameof(Color)}: {Color}, {nameof(Darkness)}: {Darkness}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preset block colours
|
||||||
|
/// </summary>
|
||||||
|
public enum BlockColors : byte
|
||||||
|
{
|
||||||
|
Default = byte.MaxValue,
|
||||||
|
White = 0,
|
||||||
|
Pink,
|
||||||
|
Purple,
|
||||||
|
Blue,
|
||||||
|
Aqua,
|
||||||
|
Green,
|
||||||
|
Lime,
|
||||||
|
Yellow,
|
||||||
|
Orange,
|
||||||
|
Red
|
||||||
|
}
|
||||||
|
}
|
17
TechbloxModdingAPI/Blocks/BlockComplexity.cs
Normal file
17
TechbloxModdingAPI/Blocks/BlockComplexity.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
using RobocraftX.Blocks;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
public record BlockComplexity(int Cpu, int Power)
|
||||||
|
{
|
||||||
|
public BlockComplexity(BlockComplexityComponent component) : this(component.cpu, component.power)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Cpu { get; } = Cpu;
|
||||||
|
public int Power { get; } = Power;
|
||||||
|
|
||||||
|
public static implicit operator BlockComplexityComponent(BlockComplexity complexity) =>
|
||||||
|
new() { cpu = complexity.Cpu, power = complexity.Power };
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
using GamecraftModdingAPI;
|
using TechbloxModdingAPI;
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Blocks
|
namespace TechbloxModdingAPI.Blocks
|
||||||
{
|
{
|
||||||
public class BlockException : GamecraftModdingAPIException
|
public class BlockException : TechbloxModdingAPIException
|
||||||
{
|
{
|
||||||
public BlockException()
|
public BlockException()
|
||||||
{
|
{
|
||||||
|
@ -41,13 +41,24 @@ namespace GamecraftModdingAPI.Blocks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BlockDoesNotExistException : BlockException
|
public class WiringException : BlockException
|
||||||
{
|
{
|
||||||
public BlockDoesNotExistException()
|
public WiringException()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlockDoesNotExistException(string message) : base(message)
|
public WiringException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class WireInvalidException : WiringException
|
||||||
|
{
|
||||||
|
public WireInvalidException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public WireInvalidException(string message) : base(message)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
383
TechbloxModdingAPI/Blocks/BlockIDs.cs
Normal file
383
TechbloxModdingAPI/Blocks/BlockIDs.cs
Normal file
|
@ -0,0 +1,383 @@
|
||||||
|
namespace TechbloxModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Possible block types
|
||||||
|
/// </summary>
|
||||||
|
public enum BlockIDs : ushort
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called "nothing" in Techblox. (DBID.NOTHING)
|
||||||
|
/// </summary>
|
||||||
|
Invalid = ushort.MaxValue,
|
||||||
|
Cube = 0,
|
||||||
|
Wedge,
|
||||||
|
QuarterPyramid,
|
||||||
|
Tetrahedron,
|
||||||
|
RoundedWedge,
|
||||||
|
RoundedQuarterPyramid,
|
||||||
|
RoundedTetrahedron,
|
||||||
|
NegativeQuarterPyramid,
|
||||||
|
NegativeTetrahedron,
|
||||||
|
RoundedNegativeQuarterPyramid,
|
||||||
|
RoundedNegativeTetrahedron,
|
||||||
|
Plate,
|
||||||
|
PlateWedge,
|
||||||
|
PlateQuarterPyramid,
|
||||||
|
PlateTetrahedron,
|
||||||
|
Sphere,
|
||||||
|
CarWheelArch = 47,
|
||||||
|
CarArchSmallFlare,
|
||||||
|
CarArchFlare,
|
||||||
|
CarArchExtrudedFlare,
|
||||||
|
Axle = 100,
|
||||||
|
Hinge,
|
||||||
|
BallJoint,
|
||||||
|
UniversalJoint,
|
||||||
|
TelescopicJoint,
|
||||||
|
DampedHingeSpring,
|
||||||
|
DampedAxleSpring,
|
||||||
|
DampedSpring,
|
||||||
|
WheelRigNoSteering,
|
||||||
|
WheelRigWithSteering,
|
||||||
|
PlateTriangle = 130,
|
||||||
|
PlateCircle,
|
||||||
|
PlateQuarterCircle,
|
||||||
|
PlateRoundedWedge,
|
||||||
|
PlateRoundedTetrahedron,
|
||||||
|
Cone,
|
||||||
|
ConeSegment,
|
||||||
|
DoubleSliced,
|
||||||
|
HalfDoubleSliced,
|
||||||
|
EighthPyramid,
|
||||||
|
Hemisphere,
|
||||||
|
WideCylinder,
|
||||||
|
WideCylinderBend,
|
||||||
|
WideCylinderT,
|
||||||
|
WideCylinderCross,
|
||||||
|
WideCylinderCorner,
|
||||||
|
NarrowCylinder,
|
||||||
|
NarrowCylinderBend,
|
||||||
|
NarrowCylinderT,
|
||||||
|
NarrowCylinderCross,
|
||||||
|
DriverSeat,
|
||||||
|
PassengerSeat,
|
||||||
|
Engine,
|
||||||
|
NarrowCylinderCorner,
|
||||||
|
PlateWideCylinder,
|
||||||
|
PlateNarrowCylinder,
|
||||||
|
PlateNegativeTetrahedron,
|
||||||
|
PlateNegativeQuarterPyramid,
|
||||||
|
PlateRoundedNegativeTetrahedron,
|
||||||
|
PlateRoundedNegativeQuarterPyramid,
|
||||||
|
HeadlampSquare,
|
||||||
|
HeadlampCircle,
|
||||||
|
HeadlampWedge,
|
||||||
|
WideCylinderDiagonal,
|
||||||
|
NarrowCylinderDiagonal,
|
||||||
|
HeadlampTetrahedron,
|
||||||
|
GoKartEngine,
|
||||||
|
Screen5X2Y2Z,
|
||||||
|
Screen5X2Y3Z,
|
||||||
|
Screen5X2Y5Z,
|
||||||
|
Screen9X2Y2Z,
|
||||||
|
Screen9X3Y2Z,
|
||||||
|
Screen9X2Y3Z,
|
||||||
|
Screen9X3Y3Z,
|
||||||
|
Screen9X2Y5Z,
|
||||||
|
Screen9X3Y5Z,
|
||||||
|
Screen11X3Y2Z,
|
||||||
|
Screen11X3Y3Z,
|
||||||
|
Screen11X3Y5Z,
|
||||||
|
Window6X2Y2Z,
|
||||||
|
Window6X3Y2Z,
|
||||||
|
Window6X2Y2ZS1,
|
||||||
|
Window6X3Y2ZS1,
|
||||||
|
Window6X2Y2ZS2,
|
||||||
|
Window6X3Y2ZS2,
|
||||||
|
Window6X2Y2ZS4,
|
||||||
|
Window6X3Y2ZS4,
|
||||||
|
FrameSquare,
|
||||||
|
FrameSkewedSquare,
|
||||||
|
FrameTriangle,
|
||||||
|
FrameSkewedTriangle,
|
||||||
|
GlassFrameSquare,
|
||||||
|
GlassFrameSkewedSquare,
|
||||||
|
GlassFrameTriangle,
|
||||||
|
GlassFrameSkewedTriangle,
|
||||||
|
GlassPlate,
|
||||||
|
GlassPlateTriangle,
|
||||||
|
GoKartWheelRigNoSteering,
|
||||||
|
GoKartWheelRigWithSteering,
|
||||||
|
GoKartSeat,
|
||||||
|
CarWheelWideProfile,
|
||||||
|
CarWheel,
|
||||||
|
GoKartWheelWideProfile,
|
||||||
|
GoKartWheel,
|
||||||
|
ANDLogicGate,
|
||||||
|
ORLogicGate,
|
||||||
|
NOTLogicGate,
|
||||||
|
NANDLogicGate,
|
||||||
|
NORLogicGate,
|
||||||
|
XORLogicGate,
|
||||||
|
XNORLogicGate,
|
||||||
|
AdderMathBlock,
|
||||||
|
SubtractorMathBlock,
|
||||||
|
MultiplierMathBlock,
|
||||||
|
DividerMathBlock,
|
||||||
|
InverterMathBlock,
|
||||||
|
AverageMathBlock,
|
||||||
|
AbsoluteMathBlock,
|
||||||
|
MinMathBlock,
|
||||||
|
MaxMathBlock,
|
||||||
|
SimpleConnector,
|
||||||
|
Motor,
|
||||||
|
AxleServo,
|
||||||
|
HingeServo,
|
||||||
|
Piston,
|
||||||
|
Button,
|
||||||
|
Switch,
|
||||||
|
Dial,
|
||||||
|
Lever,
|
||||||
|
ThreeWaySwitch,
|
||||||
|
EqualsMathBlock,
|
||||||
|
LessThanMathBlock,
|
||||||
|
LessThanOrEqualMathBlock,
|
||||||
|
GreaterThanMathBlock,
|
||||||
|
GreaterThanOrEqualMathBlock,
|
||||||
|
HatchbackWheelRigNoSteering,
|
||||||
|
HatchbackWheelRigWithSteering,
|
||||||
|
HatchbackEngine,
|
||||||
|
HatchbackWheel,
|
||||||
|
HatchbackWheelArch,
|
||||||
|
HatchbackArchSmallFlare,
|
||||||
|
HatchbackArchFlare,
|
||||||
|
CeilingStripLight,
|
||||||
|
CardboardBox,
|
||||||
|
BarrierRail,
|
||||||
|
BarrierRailEnd,
|
||||||
|
TruckWheel,
|
||||||
|
HatchbackWheelWideProfile,
|
||||||
|
TruckWheelRigWithSteering = 249,
|
||||||
|
TruckWheelRigNoSteering,
|
||||||
|
HatchbackDriverSeat,
|
||||||
|
HatchbackPassengerSeat,
|
||||||
|
FormulaEngine,
|
||||||
|
SmallGrass,
|
||||||
|
SmallGrassRoad,
|
||||||
|
GrassBridge,
|
||||||
|
SmallGrassTurn,
|
||||||
|
MediumGrassTurn,
|
||||||
|
LargeGrassTurn,
|
||||||
|
ExtraLargeGrassTurn,
|
||||||
|
TruckWheelDouble,
|
||||||
|
TruckWheelArch,
|
||||||
|
TruckArchSingleFlare,
|
||||||
|
WoodenDoorWithWindow,
|
||||||
|
TyreBarrierCorner,
|
||||||
|
TyreBarrierEdge,
|
||||||
|
TyreBarrierCenter,
|
||||||
|
AppleTree,
|
||||||
|
AppleForestTree,
|
||||||
|
FormulaWheel,
|
||||||
|
FormulaWheelRear,
|
||||||
|
AppleSapling,
|
||||||
|
GrassHill,
|
||||||
|
GrassHillInnerCorner,
|
||||||
|
GrassHillOuterCorner,
|
||||||
|
GrassRoadHill,
|
||||||
|
FormulaSeat,
|
||||||
|
SmallDirt,
|
||||||
|
SmallDirtRoad,
|
||||||
|
SmallDirtTurn,
|
||||||
|
MediumDirtTurn,
|
||||||
|
LargeDirtTurn,
|
||||||
|
ExtraLargeDirtTurn,
|
||||||
|
SmallGrid,
|
||||||
|
MonsterTruckWheel,
|
||||||
|
SmallGrassGridStart,
|
||||||
|
SmallGrassRumbleStripRoad,
|
||||||
|
SmallGrassRumbleStripEndRoad,
|
||||||
|
SmallGrassStartLine,
|
||||||
|
MonsterTruckEngine,
|
||||||
|
DirtHill,
|
||||||
|
DirtHillInnerCorner,
|
||||||
|
DirtHillOuterCorner,
|
||||||
|
BuildingWindowEdge,
|
||||||
|
BuildingWindowCorner,
|
||||||
|
BuildingWindowStraight,
|
||||||
|
BuildingWindowTJunction,
|
||||||
|
BuildingWindowCross,
|
||||||
|
BuildingWindowEdgeSill,
|
||||||
|
BuildingWindowCornerSill,
|
||||||
|
BuildingWindowTJunctionSill,
|
||||||
|
Broadleaf,
|
||||||
|
ForestBroadleaf,
|
||||||
|
AzaleaBush,
|
||||||
|
AzaleaFlowers1,
|
||||||
|
AzaleaFlowers2,
|
||||||
|
TreeStump1,
|
||||||
|
TreeStump2,
|
||||||
|
FieldJuniper,
|
||||||
|
ForestJuniper,
|
||||||
|
JuniperSapling,
|
||||||
|
JuniperSeedling,
|
||||||
|
FieldRedMaple,
|
||||||
|
RedMapleForest1,
|
||||||
|
RedMapleForest2,
|
||||||
|
RedMapleSapling,
|
||||||
|
FieldWhiteSpruce,
|
||||||
|
ForestWhiteSpruce,
|
||||||
|
WhiteSpruceSapling,
|
||||||
|
GirderBase,
|
||||||
|
GirderStraight,
|
||||||
|
GirderDiagonal,
|
||||||
|
GirderCorner,
|
||||||
|
PostBase,
|
||||||
|
PostStraight,
|
||||||
|
PostLShape,
|
||||||
|
PostTJunction,
|
||||||
|
PostCross,
|
||||||
|
PostCorner,
|
||||||
|
PostDiagonal,
|
||||||
|
DirtRock1,
|
||||||
|
DirtRock2,
|
||||||
|
DirtRock3,
|
||||||
|
DirtRock4,
|
||||||
|
DirtRoadHill,
|
||||||
|
WoodenPalette,
|
||||||
|
ElderberryBush,
|
||||||
|
BarrelCactus,
|
||||||
|
KnapweedFlower,
|
||||||
|
MarigoldFlowers,
|
||||||
|
TrampledBushyBluestep,
|
||||||
|
RoughGrass,
|
||||||
|
DogRose,
|
||||||
|
WesternSwordFern,
|
||||||
|
BackyardGrass,
|
||||||
|
ThickGrass,
|
||||||
|
FireExtinguisher,
|
||||||
|
DirtLowRamp,
|
||||||
|
DirtTabletopRamp,
|
||||||
|
MonsterTruckWheelRigNoSteering,
|
||||||
|
MonsterTruckWheelRigWithSteering,
|
||||||
|
MeadowCloudyDayAtmosphere,
|
||||||
|
BarrierRailDiagonal,
|
||||||
|
DirtHighRamp,
|
||||||
|
GrassRock1,
|
||||||
|
GrassRock2,
|
||||||
|
GrassRock3,
|
||||||
|
GrassRock4,
|
||||||
|
GreenFieldsSunnyDayAtmosphere,
|
||||||
|
RedMountainsDawnAtmosphere,
|
||||||
|
HighFantasySunriseAtmosphere,
|
||||||
|
/// <summary>
|
||||||
|
/// The grid block used by the world editor, named Small Grid like the other one
|
||||||
|
/// </summary>
|
||||||
|
SmallGridInWorldEditor,
|
||||||
|
CityDoubleCrossing,
|
||||||
|
CityDoubleCrossroads,
|
||||||
|
CitySmallDoubleJunction,
|
||||||
|
CityDoubleJunction,
|
||||||
|
CityDoubleToSingleJunction,
|
||||||
|
CitySmallDoubleRoad,
|
||||||
|
CityDoubleRoad,
|
||||||
|
CitySmallDoubleTurn,
|
||||||
|
CityLargeDoubleTurn,
|
||||||
|
CitySmallSingleTurn,
|
||||||
|
CityLargeSingleTurn,
|
||||||
|
CitySingleJunction,
|
||||||
|
CitySingleRoad,
|
||||||
|
SegoeUITextblock,
|
||||||
|
GravtracTextblock,
|
||||||
|
HauserTextblock,
|
||||||
|
TechnopollasTextblock,
|
||||||
|
CityDoubleHillRoad,
|
||||||
|
DiagonalTrackTile,
|
||||||
|
DiagonalTrackTile2,
|
||||||
|
DiagonalTransitionTile,
|
||||||
|
SplitLane,
|
||||||
|
BitBlock,
|
||||||
|
Timer,
|
||||||
|
CityNightAtmosphere,
|
||||||
|
FloodLight,
|
||||||
|
SoccerBall,
|
||||||
|
CircularWallLight,
|
||||||
|
BlueSkyAtmos,
|
||||||
|
DirtToGrassTransitionTile = 393,
|
||||||
|
DirtToGrassTransitionInnerTile,
|
||||||
|
DirtToGrassTransitionOuterTile,
|
||||||
|
DirtToGrassTransitionHillTile,
|
||||||
|
DirtToGrassTransitionRoadTile,
|
||||||
|
DirtHill2 = 399,
|
||||||
|
DirtHill3,
|
||||||
|
DirtInnerCorner2 = 402,
|
||||||
|
DirtInnerCorner3,
|
||||||
|
DirtOuterCorner2 = 405,
|
||||||
|
DirtOuterCorner3,
|
||||||
|
CityTarmacEdgeInner,
|
||||||
|
CityTarmacEdgeOuter,
|
||||||
|
CityTarmacEdgeRoad,
|
||||||
|
CityTarmac,
|
||||||
|
SmallGrassQuarterTile,
|
||||||
|
CityToRacetrackTransition,
|
||||||
|
HUDTimer,
|
||||||
|
CentreHUD,
|
||||||
|
Checkpoint,
|
||||||
|
ScoreboardHUD,
|
||||||
|
GameplaySFX,
|
||||||
|
SpawnPoint,
|
||||||
|
AreaSensor,
|
||||||
|
WorldResetter,
|
||||||
|
SmallJet,
|
||||||
|
MediumJet,
|
||||||
|
LargeJet,
|
||||||
|
DistanceSensor,
|
||||||
|
Stabilizer,
|
||||||
|
ObjectID,
|
||||||
|
ScoreToTechpointConversion,
|
||||||
|
TeamScore,
|
||||||
|
ScorePickupBlock,
|
||||||
|
SportyHatchbackDriverSeat,
|
||||||
|
SportyHatchbackPassengerSeat,
|
||||||
|
FlamingExhaust = 433,
|
||||||
|
SmokingExhaust,
|
||||||
|
StreetLamp,
|
||||||
|
Vector7HatchbackWheel,
|
||||||
|
Vector7HatchbackWheelWideProfile,
|
||||||
|
Vector7SedanWheel,
|
||||||
|
Vector7SedanWideProfile,
|
||||||
|
Vector7FormulaWheel,
|
||||||
|
Vector7FormulaWheelRear,
|
||||||
|
Vector7MonsterTruckWheel,
|
||||||
|
Vector7TruckWheel,
|
||||||
|
Vector7TruckWheelDouble,
|
||||||
|
BusSeat,
|
||||||
|
XLJet,
|
||||||
|
XXLJet,
|
||||||
|
ElectricSedanEngine,
|
||||||
|
HeadlampIndicator,
|
||||||
|
HeadlampSrip,
|
||||||
|
HeadlampStripEdge,
|
||||||
|
ConstantBlock,
|
||||||
|
CounterBlock,
|
||||||
|
SmallGridHill,
|
||||||
|
SmallGridHillInnerCorner,
|
||||||
|
SmallGridHillOuterCorner,
|
||||||
|
AimingAxleServo,
|
||||||
|
AimingHingeServo,
|
||||||
|
WeaponDisabler,
|
||||||
|
Vector7SmallJet,
|
||||||
|
Vector7MediumJet,
|
||||||
|
Vector7LargeJet,
|
||||||
|
Vector7XLJet,
|
||||||
|
Vector7XXLJet,
|
||||||
|
APCWheelRigNoSteering,
|
||||||
|
APCWheelRigWithSteering,
|
||||||
|
APCWheel,
|
||||||
|
APCSeat,
|
||||||
|
APCEngine,
|
||||||
|
DamageScoreBlock,
|
||||||
|
KillScoreBlock,
|
||||||
|
Autocannon = 480
|
||||||
|
}
|
||||||
|
}
|
46
TechbloxModdingAPI/Blocks/BlockMaterial.cs
Normal file
46
TechbloxModdingAPI/Blocks/BlockMaterial.cs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
namespace TechbloxModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
public enum BlockMaterial : byte
|
||||||
|
{
|
||||||
|
Default = byte.MaxValue,
|
||||||
|
SteelBodywork = 0,
|
||||||
|
RigidSteel,
|
||||||
|
CarbonFiber,
|
||||||
|
Plastic,
|
||||||
|
Wood = 6,
|
||||||
|
RigidSteelPainted,
|
||||||
|
RigidSteelRustedPaint,
|
||||||
|
RigidSteelHeavyRust,
|
||||||
|
SteelBodyworkMetallicPaint,
|
||||||
|
SteelBodyworkRustedPaint,
|
||||||
|
SteelBodyworkHeavyRust,
|
||||||
|
WoodVarnishedDark,
|
||||||
|
Chrome,
|
||||||
|
FenceChainLink,
|
||||||
|
ConcreteUnpainted,
|
||||||
|
Grid9x9,
|
||||||
|
CeramicTileFloor,
|
||||||
|
PlasticBumpy,
|
||||||
|
PlasticDustySmeared,
|
||||||
|
AluminiumGarageDoor,
|
||||||
|
SteelRigidScratched,
|
||||||
|
AluminiumBrushedTinted,
|
||||||
|
AluminiumSheetStained,
|
||||||
|
ConcretePaintedGrooves,
|
||||||
|
PlasticSpecklySatin,
|
||||||
|
SteelBodyworkPaintedChipped,
|
||||||
|
WoodPainted,
|
||||||
|
WoodRoughGrungy,
|
||||||
|
Boundary,
|
||||||
|
Emissive,
|
||||||
|
AircraftPanelingRivetedPainted,
|
||||||
|
AircraftPanelingRivetedMetallic,
|
||||||
|
SteelBodyworkPearlescent,
|
||||||
|
SteelBodyworkRadWrap,
|
||||||
|
SteelBodyworkGlitter,
|
||||||
|
BouncyRubber,
|
||||||
|
BouncyRubberTieDye,
|
||||||
|
BrickPainted,
|
||||||
|
FuturisticPanelingRivetedPainted,
|
||||||
|
}
|
||||||
|
}
|
256
TechbloxModdingAPI/Blocks/BlockTests.cs
Normal file
256
TechbloxModdingAPI/Blocks/BlockTests.cs
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using DataLoader;
|
||||||
|
using Svelto.Tasks;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
|
||||||
|
using TechbloxModdingAPI.Tests;
|
||||||
|
using TechbloxModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
#if TEST
|
||||||
|
/// <summary>
|
||||||
|
/// Block test cases. Not accessible in release versions.
|
||||||
|
/// </summary>
|
||||||
|
[APITestClass]
|
||||||
|
public static class BlockTests
|
||||||
|
{
|
||||||
|
[APITestCase(TestType.Game)] //At least one block must be placed for simulation to work
|
||||||
|
public static void TestPlaceNew()
|
||||||
|
{
|
||||||
|
Block newBlock = Block.PlaceNew(BlockIDs.Cube, float3.zero);
|
||||||
|
Assert.NotNull(newBlock.Id, "Newly placed block is missing Id. This should be populated when the block is placed.", "Newly placed block Id is not null, block successfully placed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[APITestCase(TestType.EditMode)]
|
||||||
|
public static void TestInitProperty()
|
||||||
|
{
|
||||||
|
Block newBlock = Block.PlaceNew(BlockIDs.Cube, float3.zero + 2);
|
||||||
|
if (!Assert.CloseTo(newBlock.Position, (float3.zero + 2), $"Newly placed block at {newBlock.Position} is expected at {Unity.Mathematics.float3.zero + 2}.", "Newly placed block position matches.")) return;
|
||||||
|
//Assert.Equal(newBlock.Exists, true, "Newly placed block does not exist, possibly because Sync() skipped/missed/failed.", "Newly placed block exists, Sync() successful.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[APITestCase(TestType.EditMode)]
|
||||||
|
public static void TestBlockIDCoverage()
|
||||||
|
{
|
||||||
|
Assert.Equal(
|
||||||
|
FullGameFields._dataDb.GetValues<CubeListData>().Keys.Select(ushort.Parse).OrderBy(id => id)
|
||||||
|
.SequenceEqual(Enum.GetValues(typeof(BlockIDs)).Cast<ushort>().OrderBy(id => id)
|
||||||
|
.Except(new[] {(ushort) BlockIDs.Invalid})), true,
|
||||||
|
"Block ID enum is different than the known block types, update needed.",
|
||||||
|
"Block ID enum matches the known block types.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Block[] blocks; // Store placed blocks as some blocks are already present as the workshop and the game save
|
||||||
|
[APITestCase(TestType.EditMode)]
|
||||||
|
public static void TestBlockIDs()
|
||||||
|
{
|
||||||
|
float3 pos = new float3();
|
||||||
|
var values = Enum.GetValues(typeof(BlockIDs));
|
||||||
|
blocks = new Block[values.Length - 1]; // Minus the invalid ID
|
||||||
|
int i = 0;
|
||||||
|
foreach (BlockIDs id in values)
|
||||||
|
{
|
||||||
|
if (id == BlockIDs.Invalid) continue;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
blocks[i++] = Block.PlaceNew(id, pos);
|
||||||
|
pos += 0.2f;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{ //Only print failed case
|
||||||
|
Assert.Fail($"Failed to place block type {id}: {e}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.Pass("Placing all possible block types succeeded.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[APITestCase(TestType.EditMode)]
|
||||||
|
public static IEnumerator<TaskContract> TestBlockProperties()
|
||||||
|
{ //Uses the result of the previous test case
|
||||||
|
yield return Yield.It;
|
||||||
|
if (blocks is null)
|
||||||
|
yield break;
|
||||||
|
for (var index = 0; index < blocks.Length; index++)
|
||||||
|
{
|
||||||
|
var block = blocks[index];
|
||||||
|
if (!block.Exists) continue;
|
||||||
|
foreach (var property in block.GetType().GetProperties())
|
||||||
|
{
|
||||||
|
//Includes specialised block properties
|
||||||
|
if (property.SetMethod == null) continue;
|
||||||
|
|
||||||
|
bool3 Float3Compare(float3 a, float3 b)
|
||||||
|
{ // From Unity reference code
|
||||||
|
return math.abs(b - a) < math.max(
|
||||||
|
0.000001f * math.max(math.abs(a), math.abs(b)),
|
||||||
|
float.Epsilon * 8
|
||||||
|
);
|
||||||
|
}
|
||||||
|
bool4 Float4Compare(float4 a, float4 b)
|
||||||
|
{ // From Unity reference code
|
||||||
|
return math.abs(b - a) < math.max(
|
||||||
|
0.000001f * math.max(math.abs(a), math.abs(b)),
|
||||||
|
float.Epsilon * 8
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var testValues = new (Type, object, Predicate<(object Value, object Default)>)[]
|
||||||
|
{
|
||||||
|
//(type, default value, predicate or null for equality)
|
||||||
|
(typeof(long), 3, null),
|
||||||
|
(typeof(int), 4, null),
|
||||||
|
(typeof(double), 5.2f, t => Math.Abs((double) t.Value - (double) t.Default) < float.Epsilon),
|
||||||
|
(typeof(float), 5.2f, t => Math.Abs((float) t.Value - (float) t.Default) < float.Epsilon),
|
||||||
|
(typeof(bool), true, t => (bool) t.Value),
|
||||||
|
(typeof(string), "Test", t => (string) t.Value == "Test"), //String equality check
|
||||||
|
(typeof(float3), (float3) 20, t => math.all(Float3Compare((float3)t.Value, (float3)t.Default))),
|
||||||
|
(typeof(BlockColor), new BlockColor(BlockColors.Aqua, 2), null),
|
||||||
|
(typeof(float4), (float4) 5, t => math.all(Float4Compare((float4)t.Value, (float4)t.Default)))
|
||||||
|
};
|
||||||
|
var propType = property.PropertyType;
|
||||||
|
if (!propType.IsValueType) continue;
|
||||||
|
(object valueToUse, Predicate<(object Value, object Default)> predicateToUse) = (null, null);
|
||||||
|
foreach (var (type, value, predicate) in testValues)
|
||||||
|
{
|
||||||
|
if (type.IsAssignableFrom(propType))
|
||||||
|
{
|
||||||
|
valueToUse = value;
|
||||||
|
predicateToUse = predicate ?? (t => Equals(t.Value, t.Default));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (propType.IsEnum)
|
||||||
|
{
|
||||||
|
var values = propType.GetEnumValues();
|
||||||
|
valueToUse = values.GetValue(values.Length / 2);
|
||||||
|
predicateToUse = t => Equals(t.Value, t.Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueToUse == null)
|
||||||
|
{
|
||||||
|
Assert.Fail($"Property {block.GetType().Name}.{property.Name} has an unknown type {propType}, test needs fixing.");
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
property.SetValue(block, valueToUse);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Assert.Fail($"Failed to set property {block.GetType().Name}.{property.Name} to {valueToUse}\n{e}");
|
||||||
|
}
|
||||||
|
object got;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
got = property.GetValue(block);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Assert.Fail($"Failed to get property {block.GetType().Name}.{property.Name}\n{e}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var attr = property.GetCustomAttribute<TestValueAttribute>();
|
||||||
|
if (!predicateToUse((got, valueToUse)) && (attr == null || !Equals(attr.PossibleValue, got)))
|
||||||
|
{
|
||||||
|
Assert.Fail($"Property {block.GetType().Name}.{property.Name} value {got} does not equal {valueToUse} for block {block}.");
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.Pass("Setting all possible properties of all registered API block types succeeded.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[APITestCase(TestType.EditMode)]
|
||||||
|
public static IEnumerator<TaskContract> TestDefaultValue()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{ //Tests shared defaults
|
||||||
|
var block = Block.PlaceNew(BlockIDs.Cube, 1);
|
||||||
|
while (!block.Exists)
|
||||||
|
yield return Yield.It;
|
||||||
|
block.Remove();
|
||||||
|
while (block.Exists)
|
||||||
|
yield return Yield.It;
|
||||||
|
if(!Assert.Equal(block.Position, default,
|
||||||
|
$"Block position default value {block.Position} is incorrect, should be 0.",
|
||||||
|
$"Block position default value {block.Position} matches default."))
|
||||||
|
yield break;
|
||||||
|
block.Position = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[APITestCase(TestType.EditMode)]
|
||||||
|
public static void TestDampedSpring()
|
||||||
|
{
|
||||||
|
Block newBlock = Block.PlaceNew(BlockIDs.DampedSpring, Unity.Mathematics.float3.zero + 1);
|
||||||
|
DampedSpring b = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler
|
||||||
|
Assert.Errorless(() => { b = (DampedSpring) newBlock; }, "Casting block to DampedSpring raised an exception: ", "Casting block to DampedSpring completed without issue.");
|
||||||
|
if (!Assert.CloseTo(b.Stiffness, 1f, $"DampedSpring.Stiffness {b.Stiffness} does not equal default value, possibly because it failed silently.", "DampedSpring.Stiffness is close enough to default.")) return;
|
||||||
|
if (!Assert.CloseTo(b.Damping, 0.1f, $"DampedSpring.Damping {b.Damping} does not equal default value, possibly because it failed silently.", "DampedSpring.Damping is close enough to default.")) return;
|
||||||
|
if (!Assert.CloseTo(b.MaxExtension, 0.3f, $"DampedSpring.MaxExtension {b.MaxExtension} does not equal default value, possibly because it failed silently.", "DampedSpring.MaxExtension is close enough to default.")) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*[APITestCase(TestType.Game)]
|
||||||
|
public static void TestMusicBlock1()
|
||||||
|
{
|
||||||
|
Block newBlock = Block.PlaceNew(BlockIDs.MusicBlock, Unity.Mathematics.float3.zero + 2);
|
||||||
|
MusicBlock b = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler
|
||||||
|
Assert.Errorless(() => { b = newBlock.Specialise<MusicBlock>(); }, "Block.Specialize<MusicBlock>() raised an exception: ", "Block.Specialize<MusicBlock>() completed without issue.");
|
||||||
|
if (!Assert.NotNull(b, "Block.Specialize<MusicBlock>() returned null, possibly because it failed silently.", "Specialized MusicBlock is not null.")) return;
|
||||||
|
if (!Assert.CloseTo(b.Volume, 100f, $"MusicBlock.Volume {b.Volume} does not equal default value, possibly because it failed silently.", "MusicBlock.Volume is close enough to default.")) return;
|
||||||
|
if (!Assert.Equal(b.TrackIndex, 0, $"MusicBlock.TrackIndex {b.TrackIndex} does not equal default value, possibly because it failed silently.", "MusicBlock.TrackIndex is equal to default.")) return;
|
||||||
|
_musicBlock = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MusicBlock _musicBlock;
|
||||||
|
|
||||||
|
[APITestCase(TestType.EditMode)]
|
||||||
|
public static void TestMusicBlock2()
|
||||||
|
{
|
||||||
|
//Block newBlock = Block.GetLastPlacedBlock();
|
||||||
|
var b = _musicBlock;
|
||||||
|
if (!Assert.NotNull(b, "Block.Specialize<MusicBlock>() returned null, possibly because it failed silently.", "Specialized MusicBlock is not null.")) return;
|
||||||
|
b.IsPlaying = true; // play sfx
|
||||||
|
if (!Assert.Equal(b.IsPlaying, true, $"MusicBlock.IsPlaying {b.IsPlaying} does not equal true, possibly because it failed silently.", "MusicBlock.IsPlaying is set properly.")) return;
|
||||||
|
if (!Assert.Equal(b.ChannelType, ChannelType.None, $"MusicBlock.ChannelType {b.ChannelType} does not equal default value, possibly because it failed silently.", "MusicBlock.ChannelType is equal to default.")) return;
|
||||||
|
//Assert.Log(b.Track.ToString());
|
||||||
|
if (!Assert.Equal(b.Track.ToString(), new Guid("3237ff8f-f5f2-4f84-8144-496ca280f8c0").ToString(), $"MusicBlock.Track {b.Track} does not equal default value, possibly because it failed silently.", "MusicBlock.Track is equal to default.")) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[APITestCase(TestType.EditMode)]
|
||||||
|
public static void TestLogicGate()
|
||||||
|
{
|
||||||
|
Block newBlock = Block.PlaceNew(BlockIDs.NOTLogicBlock, Unity.Mathematics.float3.zero + 1);
|
||||||
|
LogicGate b = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler
|
||||||
|
Assert.Errorless(() => { b = newBlock.Specialise<LogicGate>(); }, "Block.Specialize<LogicGate>() raised an exception: ", "Block.Specialize<LogicGate>() completed without issue.");
|
||||||
|
if (!Assert.NotNull(b, "Block.Specialize<LogicGate>() returned null, possibly because it failed silently.", "Specialized LogicGate is not null.")) return;
|
||||||
|
if (!Assert.Equal(b.InputCount, 1u, $"LogicGate.InputCount {b.InputCount} does not equal default value, possibly because it failed silently.", "LogicGate.InputCount is default.")) return;
|
||||||
|
if (!Assert.Equal(b.OutputCount, 1u, $"LogicGate.OutputCount {b.OutputCount} does not equal default value, possibly because it failed silently.", "LogicGate.OutputCount is default.")) return;
|
||||||
|
if (!Assert.NotNull(b, "Block.Specialize<LogicGate>() returned null, possibly because it failed silently.", "Specialized LogicGate is not null.")) return;
|
||||||
|
//if (!Assert.Equal(b.PortName(0, true), "Input", $"LogicGate.PortName(0, input:true) {b.PortName(0, true)} does not equal default value, possibly because it failed silently.", "LogicGate.PortName(0, input:true) is close enough to default.")) return;
|
||||||
|
LogicGate target = null;
|
||||||
|
if (!Assert.Errorless(() => { target = Block.PlaceNew<LogicGate>(BlockIDs.ANDLogicBlock, Unity.Mathematics.float3.zero + 2); })) return;
|
||||||
|
Wire newWire = null;
|
||||||
|
if (!Assert.Errorless(() => { newWire = b.Connect(0, target, 0);})) return;
|
||||||
|
if (!Assert.NotNull(newWire, "SignalingBlock.Connect(...) returned null, possible because it failed silently.", "SignalingBlock.Connect(...) returned a non-null value.")) return;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*[APITestCase(TestType.EditMode)]
|
||||||
|
public static void TestSpecialiseError()
|
||||||
|
{
|
||||||
|
Block newBlock = Block.PlaceNew(BlockIDs.Bench, new float3(1, 1, 1));
|
||||||
|
if (Assert.Errorful<BlockTypeException>(() => newBlock.Specialise<MusicBlock>(), "Block.Specialise<MusicBlock>() was expected to error on a bench block.", "Block.Specialise<MusicBlock>() errored as expected for a bench block.")) return;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
71
TechbloxModdingAPI/Blocks/DampedSpring.cs
Normal file
71
TechbloxModdingAPI/Blocks/DampedSpring.cs
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
namespace TechbloxModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
|
||||||
|
public class DampedSpring : SignalingBlock
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a(n) DampedSpring object representing an existing block.
|
||||||
|
/// </summary>
|
||||||
|
public DampedSpring(EGID egid) :
|
||||||
|
base(egid)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a(n) DampedSpring object representing an existing block.
|
||||||
|
/// </summary>
|
||||||
|
public DampedSpring(uint id) :
|
||||||
|
base(new EGID(id, CommonExclusiveGroups.DAMPEDSPRING_BLOCK_GROUP))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the DampedSpring's Stiffness property. Tweakable stat.
|
||||||
|
/// </summary>
|
||||||
|
public float Stiffness
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<RobocraftX.Blocks.TweakableJointDampingComponent>(this).stiffness;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<RobocraftX.Blocks.TweakableJointDampingComponent>(this).stiffness = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the DampedSpring's Damping property. Tweakable stat.
|
||||||
|
/// </summary>
|
||||||
|
public float Damping
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<RobocraftX.Blocks.TweakableJointDampingComponent>(this).damping;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<RobocraftX.Blocks.TweakableJointDampingComponent>(this).damping = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the DampedSpring's MaxExtension property. Tweakable stat.
|
||||||
|
/// </summary>
|
||||||
|
public float MaxExtension
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<RobocraftX.Blocks.DampedSpringReadOnlyStruct>(this).maxExtent;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<RobocraftX.Blocks.DampedSpringReadOnlyStruct>(this).maxExtent = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
382
TechbloxModdingAPI/Blocks/Engine.cs
Normal file
382
TechbloxModdingAPI/Blocks/Engine.cs
Normal file
|
@ -0,0 +1,382 @@
|
||||||
|
namespace TechbloxModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
|
||||||
|
public class Engine : SignalingBlock
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a(n) Engine object representing an existing block.
|
||||||
|
/// </summary>
|
||||||
|
public Engine(EGID egid) :
|
||||||
|
base(egid)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a(n) Engine object representing an existing block.
|
||||||
|
/// </summary>
|
||||||
|
public Engine(uint id) :
|
||||||
|
base(new EGID(id, CommonExclusiveGroups.ENGINE_BLOCK_BUILD_GROUP))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*/// <summary> - TODO: Internal struct access
|
||||||
|
/// Gets or sets the Engine's On property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public bool On
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).engineOn;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).engineOn = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's CurrentGear property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public int CurrentGear
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).currentGear;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).currentGear = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's GearChangeCountdown property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public float GearChangeCountdown
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).gearChangeCountdown;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).gearChangeCountdown = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's CurrentRpmAV property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public float CurrentRpmAV
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).currentRpmAV;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).currentRpmAV = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's CurrentRpmLV property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public float CurrentRpmLV
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).currentRpmLV;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).currentRpmLV = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's TargetRpmAV property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public float TargetRpmAV
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).targetRpmAV;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).targetRpmAV = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's TargetRpmLV property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public float TargetRpmLV
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).targetRpmLV;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).targetRpmLV = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's CurrentTorque property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public float CurrentTorque
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).currentTorque;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).currentTorque = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's TotalWheelVelocityAV property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public float TotalWheelVelocityAV
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).totalWheelVelocityAV;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).totalWheelVelocityAV = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's TotalWheelVelocityLV property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public float TotalWheelVelocityLV
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).totalWheelVelocityLV;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).totalWheelVelocityLV = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's TotalWheelCount property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public int TotalWheelCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).totalWheelCount;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).totalWheelCount = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's LastGearUpInput property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public bool LastGearUpInput
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).lastGearUpInput;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).lastGearUpInput = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's LastGearDownInput property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public bool LastGearDownInput
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).lastGearDownInput;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).lastGearDownInput = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's ManualToAutoGearCoolOffCounter property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public float ManualToAutoGearCoolOffCounter
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).manualToAutoGearCoolOffCounter;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).manualToAutoGearCoolOffCounter = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's Load property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public float Load
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).load;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).load = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's Power property. Tweakable stat.
|
||||||
|
/// </summary>
|
||||||
|
public float Power
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockTweakableComponent>(this).power;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockTweakableComponent>(this).power = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's AutomaticGears property. Tweakable stat.
|
||||||
|
/// </summary>
|
||||||
|
public bool AutomaticGears
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockTweakableComponent>(this).automaticGears;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockTweakableComponent>(this).automaticGears = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's GearChangeTime property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public float GearChangeTime
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockReadonlyComponent>(this).gearChangeTime;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockReadonlyComponent>(this).gearChangeTime = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's MinRpm property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public float MinRpm
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockReadonlyComponent>(this).minRpm;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockReadonlyComponent>(this).minRpm = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's MaxRpm property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public float MaxRpm
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockReadonlyComponent>(this).maxRpm;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockReadonlyComponent>(this).maxRpm = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Engine's GearDownRpms property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public float[] GearDownRpms
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockReadonlyComponent>(this).gearDownRpms.ToManagedArray<float>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's GearUpRpm property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public float GearUpRpm
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockReadonlyComponent>(this).gearUpRpm;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockReadonlyComponent>(this).gearUpRpm = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's MaxRpmChange property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public float MaxRpmChange
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockReadonlyComponent>(this).maxRpmChange;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockReadonlyComponent>(this).maxRpmChange = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Engine's ManualToAutoGearCoolOffTime property. May not be saved.
|
||||||
|
/// </summary>
|
||||||
|
public float ManualToAutoGearCoolOffTime
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockReadonlyComponent>(this).manualToAutoGearCoolOffTime;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockReadonlyComponent>(this).manualToAutoGearCoolOffTime = value;
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
105
TechbloxModdingAPI/Blocks/Engines/BlockCloneEngine.cs
Normal file
105
TechbloxModdingAPI/Blocks/Engines/BlockCloneEngine.cs
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using Gamecraft.Wires;
|
||||||
|
using HarmonyLib;
|
||||||
|
using RobocraftX.Blocks;
|
||||||
|
using RobocraftX.Character;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using Svelto.DataStructures;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using TechbloxModdingAPI.Engines;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
{
|
||||||
|
public class BlockCloneEngine : IApiEngine
|
||||||
|
{
|
||||||
|
private static Type copyEngineType =
|
||||||
|
AccessTools.TypeByName("Gamecraft.GUI.Tweaks.Engines.CopyTweaksOnPickEngine");
|
||||||
|
private static Type copyWireEngineType =
|
||||||
|
AccessTools.TypeByName("Gamecraft.Wires.WireConnectionCopyOnPickEngine");
|
||||||
|
private static Type createWireEngineType =
|
||||||
|
AccessTools.TypeByName("RobocraftX.GUI.Wires.WireConnectionCreateOnPlaceEngine");
|
||||||
|
|
||||||
|
private MethodBase copyFromBlock = AccessTools.Method(copyEngineType, "CopyTweaksFromBlock");
|
||||||
|
private MethodBase copyToBlock = AccessTools.Method(copyEngineType, "ApplyTweaksToPlacedBlock");
|
||||||
|
private MethodBase copyWireFromBlock = AccessTools.Method(copyWireEngineType, "CopyWireInputsAndOutputs");
|
||||||
|
private MethodBase copyWireToBlock = AccessTools.Method(createWireEngineType, "PlaceWiresOnPlaceNewCube");
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { get; set; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyBlockStats(EGID sourceID, EGID targetID)
|
||||||
|
{
|
||||||
|
var allCharacters = (LocalFasterReadOnlyList<ExclusiveGroupStruct>) CharacterExclusiveGroups.AllCharacters;
|
||||||
|
foreach (var ((pickedBlockColl, count), _) in entitiesDB.QueryEntities<PickedBlockExtraDataStruct>(allCharacters))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
ref PickedBlockExtraDataStruct pickedBlock = ref pickedBlockColl[i];
|
||||||
|
var oldStruct = pickedBlock;
|
||||||
|
pickedBlock.pickedBlockEntityID = sourceID;
|
||||||
|
pickedBlock.placedBlockEntityID = targetID;
|
||||||
|
pickedBlock.placedBlockTweaksMustCopy = true;
|
||||||
|
if (entitiesDB.Exists<BlockTagEntityStruct>(pickedBlock.pickedBlockEntityID)
|
||||||
|
&& entitiesDB.Exists<BlockTagEntityStruct>(pickedBlock.placedBlockEntityID))
|
||||||
|
{
|
||||||
|
copyFromBlock.Invoke(Patch.copyEngine, new object[] {pickedBlock.ID, pickedBlock});
|
||||||
|
|
||||||
|
uint playerID = Player.LocalPlayer.Id;
|
||||||
|
var parameters = new object[] {playerID, pickedBlock};
|
||||||
|
copyWireFromBlock.Invoke(Patch.copyWireEngine, parameters);
|
||||||
|
pickedBlock = (PickedBlockExtraDataStruct) parameters[1]; //ref arg
|
||||||
|
|
||||||
|
copyToBlock.Invoke(Patch.copyEngine, new object[] {pickedBlock.ID, pickedBlock});
|
||||||
|
|
||||||
|
ExclusiveGroupStruct group = BuildModeWiresGroups.WIRES_COPY_GROUP + playerID;
|
||||||
|
copyWireToBlock.Invoke(Patch.createWireEngine, new object[] {group, pickedBlock.ID});
|
||||||
|
|
||||||
|
pickedBlock.placedBlockTweaksMustCopy = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pickedBlock = oldStruct; //Make sure to not interfere with the game - Although that might not be the case with the wire copying
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch]
|
||||||
|
private static class Patch
|
||||||
|
{
|
||||||
|
public static object copyEngine;
|
||||||
|
public static object copyWireEngine;
|
||||||
|
public static object createWireEngine;
|
||||||
|
|
||||||
|
public static void Postfix(object __instance)
|
||||||
|
{
|
||||||
|
if (__instance.GetType() == copyEngineType)
|
||||||
|
copyEngine = __instance;
|
||||||
|
else if (__instance.GetType() == copyWireEngineType)
|
||||||
|
copyWireEngine = __instance;
|
||||||
|
else if (__instance.GetType() == createWireEngineType)
|
||||||
|
createWireEngine = __instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<MethodBase> TargetMethods()
|
||||||
|
{
|
||||||
|
return new[]
|
||||||
|
{
|
||||||
|
AccessTools.GetDeclaredConstructors(copyEngineType)[0],
|
||||||
|
AccessTools.GetDeclaredConstructors(copyWireEngineType)[0],
|
||||||
|
AccessTools.GetDeclaredConstructors(createWireEngineType)[0]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; } = "TechbloxModdingAPIBlockCloneGameEngine";
|
||||||
|
public bool isRemovable { get; } = false;
|
||||||
|
}
|
||||||
|
}
|
292
TechbloxModdingAPI/Blocks/Engines/BlockEngine.cs
Normal file
292
TechbloxModdingAPI/Blocks/Engines/BlockEngine.cs
Normal file
|
@ -0,0 +1,292 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using HarmonyLib;
|
||||||
|
|
||||||
|
using Gamecraft.ColourPalette;
|
||||||
|
using Gamecraft.Wires;
|
||||||
|
using RobocraftX.Blocks;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.Physics;
|
||||||
|
using RobocraftX.Rendering;
|
||||||
|
using RobocraftX.Rendering.GPUI;
|
||||||
|
using Svelto.DataStructures;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Svelto.ECS.EntityStructs;
|
||||||
|
using Svelto.ECS.Experimental;
|
||||||
|
using Svelto.ECS.Hybrid;
|
||||||
|
using Techblox.BuildingDrone;
|
||||||
|
using Techblox.ObjectIDBlockServer;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
|
||||||
|
using TechbloxModdingAPI.Engines;
|
||||||
|
using TechbloxModdingAPI.Utility;
|
||||||
|
using TechbloxModdingAPI.Utility.ECS;
|
||||||
|
using PrefabsID = RobocraftX.Common.PrefabsID;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Engine for executing general block actions
|
||||||
|
/// </summary>
|
||||||
|
public partial class BlockEngine : IApiEngine
|
||||||
|
{
|
||||||
|
public string Name { get; } = "TechbloxModdingAPIBlockGameEngine";
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public bool isRemovable => false;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Block[] GetConnectedBlocks(EGID blockID)
|
||||||
|
{
|
||||||
|
if (!BlockExists(blockID)) return Array.Empty<Block>();
|
||||||
|
Stack<EGID> cubeStack = new Stack<EGID>();
|
||||||
|
FasterList<EGID> cubes = new FasterList<EGID>(10);
|
||||||
|
var coll = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
|
||||||
|
foreach (var ((ecoll, count), _) in coll)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
ecoll[i].areConnectionsAssigned = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: GetConnectedCubesUtility
|
||||||
|
/*ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubeStack, cubes,
|
||||||
|
(in GridConnectionsEntityStruct _) => false);*/
|
||||||
|
|
||||||
|
var ret = new Block[cubes.count];
|
||||||
|
for (int i = 0; i < cubes.count; i++)
|
||||||
|
ret[i] = Block.New(cubes[i]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float4 ConvertBlockColor(byte index) => index == byte.MaxValue
|
||||||
|
? new float4(-1f, -1f, -1f, -1f)
|
||||||
|
: entitiesDB.QueryEntity<PaletteEntryEntityStruct>(index,
|
||||||
|
ColourPaletteExclusiveGroups.COLOUR_PALETTE_GROUP).Colour;
|
||||||
|
|
||||||
|
public OptionalRef<T> GetBlockInfoOptional<T>(Block block) where T : unmanaged, IEntityComponent
|
||||||
|
{
|
||||||
|
return entitiesDB.QueryEntityOptional<T>(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref T GetBlockInfo<T>(Block block) where T : unmanaged, IEntityComponent
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
if (!typeof(BlockTagEntityStruct).IsAssignableFrom(typeof(T)) && block.Exists && block.InitData.Valid)
|
||||||
|
throw new ArgumentException("The block exists but the init data has not been removed!");
|
||||||
|
#endif
|
||||||
|
return ref entitiesDB.QueryEntityOrDefault<T>(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal ref T GetBlockInfo<T>(EcsObjectBase obj) where T : unmanaged, IEntityComponent
|
||||||
|
{
|
||||||
|
return ref entitiesDB.QueryEntityOrDefault<T>(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref T GetBlockInfoViewComponent<T>(Block block) where T : struct, IEntityViewComponent
|
||||||
|
{
|
||||||
|
return ref entitiesDB.QueryEntityOrDefault<T>(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal object GetBlockInfo(Block block, Type type, string name)
|
||||||
|
{
|
||||||
|
var opt = AccessTools.Method(typeof(NativeApiExtensions), "QueryEntityOptional",
|
||||||
|
new[] { typeof(EntitiesDB), typeof(EcsObjectBase), typeof(ExclusiveGroupStruct) }, new[] { type })
|
||||||
|
.Invoke(null, new object[] { entitiesDB, block, null });
|
||||||
|
var str = AccessTools.Property(opt.GetType(), "Value").GetValue(opt);
|
||||||
|
return AccessTools.Field(str.GetType(), name).GetValue(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void SetBlockInfo(Block block, Type type, string name, object value)
|
||||||
|
{
|
||||||
|
var opt = AccessTools.Method(typeof(BlockEngine), "GetBlockInfoOptional", generics: new[] { type })
|
||||||
|
.Invoke(this, new object[] { block });
|
||||||
|
var prop = AccessTools.Property(opt.GetType(), "Value");
|
||||||
|
var str = prop.GetValue(opt);
|
||||||
|
AccessTools.Field(str.GetType(), name).SetValue(str, value);
|
||||||
|
prop.SetValue(opt, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateDisplayedBlock(EGID id)
|
||||||
|
{
|
||||||
|
if (!BlockExists(id)) return;
|
||||||
|
var pos = entitiesDB.QueryEntity<PositionEntityStruct>(id);
|
||||||
|
var rot = entitiesDB.QueryEntity<RotationEntityStruct>(id);
|
||||||
|
var scale = entitiesDB.QueryEntity<ScalingEntityStruct>(id);
|
||||||
|
var skew = entitiesDB.QueryEntity<SkewComponent>(id);
|
||||||
|
entitiesDB.QueryEntity<RenderingDataStruct>(id).matrix =
|
||||||
|
math.mul(float4x4.TRS(pos.position, rot.rotation, scale.scale), skew.skewMatrix);
|
||||||
|
entitiesDB.PublishEntityChangeDelayed<GFXPrefabEntityStructGPUI>(id); // Signal a prefab change so it updates the render buffers
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void UpdatePrefab(Block block, byte material, bool flipped)
|
||||||
|
{
|
||||||
|
var prefabAssetIDOpt = entitiesDB.QueryEntityOptional<PrefabAssetIDComponent>(block);
|
||||||
|
uint prefabAssetID = prefabAssetIDOpt
|
||||||
|
? prefabAssetIDOpt.Get().prefabAssetID
|
||||||
|
: uint.MaxValue;
|
||||||
|
if (prefabAssetID == uint.MaxValue)
|
||||||
|
{
|
||||||
|
if (entitiesDB.QueryEntityOptional<BlockTagEntityStruct>(block)) //The block exists
|
||||||
|
throw new BlockException("Prefab asset ID not found for block " + block); //Set by the game
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint prefabId =
|
||||||
|
PrefabsID.GetOrAddPrefabID((ushort) prefabAssetID, material, 1, flipped);
|
||||||
|
entitiesDB.QueryEntityOrDefault<GFXPrefabEntityStructGPUI>(block).prefabID = prefabId;
|
||||||
|
if (block.Exists)
|
||||||
|
{
|
||||||
|
entitiesDB.PublishEntityChangeDelayed<CubeMaterialStruct>(block.Id);
|
||||||
|
entitiesDB.PublishEntityChangeDelayed<GFXPrefabEntityStructGPUI>(block.Id);
|
||||||
|
|
||||||
|
ref BuildingActionComponent local =
|
||||||
|
ref entitiesDB.QueryEntity<BuildingActionComponent>(BuildingDroneUtility
|
||||||
|
.GetLocalBuildingDrone(entitiesDB).ToEGID(entitiesDB));
|
||||||
|
local.buildAction = BuildAction.ChangeMaterial;
|
||||||
|
local.targetPosition = block.Position;
|
||||||
|
this.entitiesDB.PublishEntityChangeDelayed<BuildingActionComponent>(local.ID);
|
||||||
|
}
|
||||||
|
//Phyiscs prefab: prefabAssetID, set on block creation from the CubeListData
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateBlockColor(EGID id)
|
||||||
|
{
|
||||||
|
entitiesDB.PublishEntityChangeDelayed<ColourParameterEntityStruct>(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool BlockExists(EGID blockID)
|
||||||
|
{
|
||||||
|
return entitiesDB.Exists<BlockTagEntityStruct>(blockID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimBody[] GetSimBodiesFromID(byte id)
|
||||||
|
{
|
||||||
|
var ret = new FasterList<SimBody>(4);
|
||||||
|
var oids = entitiesDB.QueryEntitiesOptional<ObjectIdEntityStruct>(ObjectIDBlockExclusiveGroups.OBJECT_ID_BLOCK_GROUP);
|
||||||
|
EGIDMapper<GridConnectionsEntityStruct>? connections = null;
|
||||||
|
foreach (var oid in oids)
|
||||||
|
{
|
||||||
|
if (oid.Get().objectId != id) continue;
|
||||||
|
if (!connections.HasValue) //Would need reflection to get the group from the build group otherwise
|
||||||
|
connections = entitiesDB.QueryMappedEntities<GridConnectionsEntityStruct>(oid.EGID.groupID);
|
||||||
|
//var rid = connections.Value.Entity(tag.ID.entityID).machineRigidBodyId;
|
||||||
|
/*foreach (var rb in ret) - TODO
|
||||||
|
{
|
||||||
|
if (rb.Id.entityID == rid)
|
||||||
|
goto DUPLICATE; //Multiple Object Identifiers on one rigid body
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.Add(new SimBody(rid));
|
||||||
|
DUPLICATE: ;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimBody[] GetConnectedSimBodies(uint id)
|
||||||
|
{
|
||||||
|
var (joints, count) = entitiesDB.QueryEntities<JointEntityStruct>(MachineSimulationGroups.JOINTS_GROUP);
|
||||||
|
var list = new FasterList<SimBody>(4);
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
ref var joint = ref joints[i];
|
||||||
|
if (joint.isBroken) continue;
|
||||||
|
/*if (joint.connectedEntityA == id) list.Add(new SimBody(joint.connectedEntityB)); - TODO:
|
||||||
|
else if (joint.connectedEntityB == id) list.Add(new SimBody(joint.connectedEntityA));*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimBody[] GetClusterBodies(uint cid)
|
||||||
|
{
|
||||||
|
var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
|
||||||
|
var bodies = new HashSet<uint>();
|
||||||
|
foreach (var ((coll, count), _) in groups)
|
||||||
|
{
|
||||||
|
for (var index = 0; index < count; index++)
|
||||||
|
{
|
||||||
|
var conn = coll[index];
|
||||||
|
/*if (conn.clusterId == cid) - TODO
|
||||||
|
bodies.Add(conn.machineRigidBodyId);*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bodies.Select(id => new SimBody(id, cid)).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public EGID? FindBlockEGID(uint id)
|
||||||
|
{
|
||||||
|
var groups = entitiesDB.FindGroups<BlockTagEntityStruct>();
|
||||||
|
foreach (ExclusiveGroupStruct group in groups)
|
||||||
|
{
|
||||||
|
if (entitiesDB.Exists<BlockTagEntityStruct>(id, group))
|
||||||
|
return new EGID(id, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cluster GetCluster(uint sbid)
|
||||||
|
{
|
||||||
|
var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
|
||||||
|
foreach (var ((coll, count), _) in groups)
|
||||||
|
{
|
||||||
|
for (var index = 0; index < count; index++)
|
||||||
|
{
|
||||||
|
var conn = coll[index];
|
||||||
|
//Static blocks don't have a cluster ID but the cluster destruction manager should have one
|
||||||
|
/*if (conn.machineRigidBodyId == sbid && conn.clusterId != uint.MaxValue) - TODO:
|
||||||
|
return new Cluster(conn.clusterId);*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Block[] GetBodyBlocks(uint sbid)
|
||||||
|
{
|
||||||
|
var groups = entitiesDB.FindGroups<GridConnectionsEntityStruct>();
|
||||||
|
groups = new QueryGroups(groups).Except(CommonExclusiveGroups.DISABLED_JOINTS_IN_SIM_GROUP).Evaluate().result;
|
||||||
|
var set = new HashSet<Block>();
|
||||||
|
foreach (var ((coll, tags, count), _) in entitiesDB.QueryEntities<GridConnectionsEntityStruct, BlockTagEntityStruct>(groups))
|
||||||
|
{
|
||||||
|
for (var index = 0; index < count; index++)
|
||||||
|
{
|
||||||
|
var conn = coll[index];
|
||||||
|
/*if (conn.machineRigidBodyId == sbid) - TODO
|
||||||
|
set.Add(Block.New(tags[index].ID));*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return set.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectID[] GetObjectIDsFromID(byte id)
|
||||||
|
{
|
||||||
|
if (!entitiesDB.HasAny<ObjectIDTweakableComponent>(ObjectIDBlockExclusiveGroups.OBJECT_ID_BLOCK_GROUP))
|
||||||
|
return Array.Empty<ObjectID>();
|
||||||
|
|
||||||
|
var ret = new FasterList<ObjectID>(4);
|
||||||
|
var oids = entitiesDB.QueryEntitiesOptional<ObjectIDTweakableComponent>(ObjectIDBlockExclusiveGroups.OBJECT_ID_BLOCK_GROUP);
|
||||||
|
foreach (var oid in oids)
|
||||||
|
{
|
||||||
|
if (oid.Get().objectIDToTrigger == id)
|
||||||
|
ret.Add(new ObjectID(oid.EGID));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
TechbloxModdingAPI/Blocks/Engines/BlockEventsEngine.cs
Normal file
47
TechbloxModdingAPI/Blocks/Engines/BlockEventsEngine.cs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using RobocraftX.Blocks;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
using TechbloxModdingAPI.Engines;
|
||||||
|
using TechbloxModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
{
|
||||||
|
public class BlockEventsEngine : IReactionaryEngine<BlockTagEntityStruct>
|
||||||
|
{
|
||||||
|
public WrappedHandler<BlockPlacedRemovedEventArgs> Placed;
|
||||||
|
public WrappedHandler<BlockPlacedRemovedEventArgs> Removed;
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { get; set; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; } = "TechbloxModdingAPIBlockEventsEngine";
|
||||||
|
public bool isRemovable { get; } = false;
|
||||||
|
|
||||||
|
public void Add(ref BlockTagEntityStruct entityComponent, EGID egid)
|
||||||
|
{
|
||||||
|
Placed.Invoke(this, new BlockPlacedRemovedEventArgs {ID = egid});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(ref BlockTagEntityStruct entityComponent, EGID egid)
|
||||||
|
{
|
||||||
|
Removed.Invoke(this, new BlockPlacedRemovedEventArgs {ID = egid});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct BlockPlacedRemovedEventArgs
|
||||||
|
{
|
||||||
|
public EGID ID;
|
||||||
|
private Block block;
|
||||||
|
|
||||||
|
public Block Block => block ??= Block.New(ID);
|
||||||
|
}
|
||||||
|
}
|
404
TechbloxModdingAPI/Blocks/Engines/BlueprintEngine.cs
Normal file
404
TechbloxModdingAPI/Blocks/Engines/BlueprintEngine.cs
Normal file
|
@ -0,0 +1,404 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using Gamecraft.Blocks.BlockGroups;
|
||||||
|
using Gamecraft.GUI.Blueprints;
|
||||||
|
using HarmonyLib;
|
||||||
|
using RobocraftX.Blocks;
|
||||||
|
using RobocraftX.Blocks.Ghost;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.CR.MachineEditing.BoxSelect;
|
||||||
|
using RobocraftX.CR.MachineEditing.BoxSelect.ClipboardOperations;
|
||||||
|
using RobocraftX.Physics;
|
||||||
|
using RobocraftX.Rendering;
|
||||||
|
using RobocraftX.Rendering.GPUI;
|
||||||
|
using Svelto.DataStructures;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Svelto.ECS.DataStructures;
|
||||||
|
using Svelto.ECS.EntityStructs;
|
||||||
|
using Svelto.ECS.Native;
|
||||||
|
using Svelto.ECS.Serialization;
|
||||||
|
using Techblox.Blocks.Connections;
|
||||||
|
using TechbloxModdingAPI.Engines;
|
||||||
|
using TechbloxModdingAPI.Utility;
|
||||||
|
using TechbloxModdingAPI.Utility.ECS;
|
||||||
|
using Unity.Collections;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
using UnityEngine;
|
||||||
|
using Allocator = Svelto.Common.Allocator;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
{
|
||||||
|
public class BlueprintEngine : IFactoryEngine
|
||||||
|
{
|
||||||
|
private readonly MethodInfo getBlocksFromGroup =
|
||||||
|
AccessTools.Method("RobocraftX.CR.MachineEditing.PlaceBlockUtility:GetBlocksSharingBlockgroup");
|
||||||
|
|
||||||
|
private NativeDynamicArray selectedBlocksInGroup;
|
||||||
|
private NativeHashSet<ulong> removedConnections = new NativeHashSet<ulong>();
|
||||||
|
private int addingToBlockGroup = -1;
|
||||||
|
|
||||||
|
private static readonly Type PlaceBlueprintUtilityType =
|
||||||
|
AccessTools.TypeByName("RobocraftX.CR.MachineEditing.PlaceBlueprintUtility");
|
||||||
|
private static readonly FieldInfo LocalBlockMap =
|
||||||
|
AccessTools.DeclaredField(PlaceBlueprintUtilityType, "_localBlockMap");
|
||||||
|
private static readonly MethodInfo BuildBlock = AccessTools.Method(PlaceBlueprintUtilityType, "BuildBlock");
|
||||||
|
private static readonly MethodInfo BuildWires = AccessTools.Method(PlaceBlueprintUtilityType, "BuildWires");
|
||||||
|
private static readonly Type SerializeGhostBlueprintType =
|
||||||
|
AccessTools.TypeByName("RobocraftX.CR.MachineEditing.BoxSelect.SerializeGhostChildrenOnAddEngine");
|
||||||
|
private static readonly MethodInfo SerializeGhostBlueprint =
|
||||||
|
AccessTools.Method(SerializeGhostBlueprintType, "SerializeClipboardGhostEntities");
|
||||||
|
|
||||||
|
private static NativeEntityRemove nativeBlockRemove;
|
||||||
|
private static NativeEntityRemove nativeConnectionRemove;
|
||||||
|
private static MachineGraphConnectionEntityFactory connectionFactory;
|
||||||
|
private static IEntityFunctions entityFunctions;
|
||||||
|
private static ClipboardSerializationDataResourceManager clipboardManager;
|
||||||
|
private static IEntitySerialization entitySerialization;
|
||||||
|
private static IEntityFactory entityFactory;
|
||||||
|
private static FasterList<EGID> globalBlockMap;
|
||||||
|
private static object SerializeGhostBlueprintInstance;
|
||||||
|
private static GhostChildEntityFactory BuildGhostBlueprintFactory;
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
selectedBlocksInGroup = NativeDynamicArray.Alloc<EGID>(Allocator.Persistent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { get; set; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
selectedBlocksInGroup.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Block[] GetBlocksFromGroup(EGID blockID, out float3 pos, out quaternion rot)
|
||||||
|
{
|
||||||
|
var blockPos = default(float3);
|
||||||
|
var blockRot = default(quaternion);
|
||||||
|
var parameters = new object[] {blockID, selectedBlocksInGroup, entitiesDB, blockPos, blockRot};
|
||||||
|
getBlocksFromGroup.Invoke(null, parameters);
|
||||||
|
pos = (float3) parameters[3];
|
||||||
|
rot = (quaternion) parameters[4];
|
||||||
|
int count = selectedBlocksInGroup.Count<EGID>();
|
||||||
|
var ret = new Block[count];
|
||||||
|
for (uint i = 0; i < count; i++)
|
||||||
|
ret[i] = Block.New(selectedBlocksInGroup.Get<EGID>(i));
|
||||||
|
selectedBlocksInGroup.FastClear();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveBlockGroup(int id)
|
||||||
|
{
|
||||||
|
BlockGroupUtility.RemoveAllBlocksInBlockGroup(id, entitiesDB, removedConnections, nativeBlockRemove,
|
||||||
|
nativeConnectionRemove, connectionFactory, default).Complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CreateBlockGroup(float3 position, quaternion rotation)
|
||||||
|
{
|
||||||
|
int nextFilterId = BlockGroupUtility.NextFilterId;
|
||||||
|
Factory.BuildEntity<BlockGroupEntityDescriptor>((uint) nextFilterId,
|
||||||
|
BlockGroupExclusiveGroups.BlockGroupEntityGroup).Init(new BlockGroupTransformEntityComponent
|
||||||
|
{
|
||||||
|
blockGroupGridRotation = rotation,
|
||||||
|
blockGroupGridPosition = position
|
||||||
|
});
|
||||||
|
return nextFilterId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddBlockToGroup(EGID blockID, int groupID)
|
||||||
|
{
|
||||||
|
if (globalBlockMap == null)
|
||||||
|
globalBlockMap = FullGameFields._deserialisedBlockMap;
|
||||||
|
if (groupID != addingToBlockGroup)
|
||||||
|
{
|
||||||
|
Logging.MetaDebugLog("Changing current block group from " + addingToBlockGroup + " to " + groupID);
|
||||||
|
addingToBlockGroup = groupID;
|
||||||
|
globalBlockMap.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
globalBlockMap.Add(blockID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SelectBlueprint(uint resourceID)
|
||||||
|
{
|
||||||
|
if (resourceID == uint.MaxValue)
|
||||||
|
BlueprintUtil.UnselectBlueprint(entitiesDB);
|
||||||
|
else
|
||||||
|
BlueprintUtil.SelectBlueprint(entitiesDB, resourceID, false, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint CreateBlueprint()
|
||||||
|
{
|
||||||
|
uint index = clipboardManager.AllocateSerializationData();
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReplaceBlueprint(uint playerID, uint blueprintID, ICollection<Block> selected, float3 pos, quaternion rot)
|
||||||
|
{
|
||||||
|
var blockIDs = new EGID[selected.Count];
|
||||||
|
using (var enumerator = selected.GetEnumerator())
|
||||||
|
{
|
||||||
|
for (var i = 0; enumerator.MoveNext(); i++)
|
||||||
|
{
|
||||||
|
var block = enumerator.Current;
|
||||||
|
blockIDs[i] = block.Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var serializationData = clipboardManager.GetSerializationData(blueprintID);
|
||||||
|
SelectionSerializationUtility.ClearClipboard(playerID, entitiesDB, entityFunctions, serializationData.blueprintData, -1);
|
||||||
|
if (selected.Count == 0)
|
||||||
|
return;
|
||||||
|
//ref BlockGroupTransformEntityComponent groupTransform = ref EntityNativeDBExtensions.QueryEntity<BlockGroupTransformEntityComponent>(entitiesDb, (uint) local1.currentBlockGroup, BlockGroupExclusiveGroups.BlockGroupEntityGroup);
|
||||||
|
//ref ColliderAabb collider = ref EntityNativeDBExtensions.QueryEntity<ColliderAabb>(entitiesDB, (uint) groupID, BlockGroupExclusiveGroups.BlockGroupEntityGroup);
|
||||||
|
//float3 bottomOffset = PlaceBlockUtility.GetBottomOffset(collider);
|
||||||
|
//var rootPosition = math.mul(groupTransform.blockGroupGridRotation, bottomOffset) + groupTransform.blockGroupGridPosition;
|
||||||
|
//var rootRotation = groupTransform.blockGroupGridRotation;
|
||||||
|
|
||||||
|
clipboardManager.SetGhostSerialized(blueprintID, false);
|
||||||
|
SelectionSerializationUtility.CopySelectionToClipboard(playerID, entitiesDB,
|
||||||
|
serializationData.blueprintData, entitySerialization, entityFactory, blockIDs,
|
||||||
|
(uint) blockIDs.Length, pos, rot, -1);
|
||||||
|
BuildGhostBlueprint(selected, pos, rot, playerID);
|
||||||
|
SerializeGhostBlueprint.Invoke(SerializeGhostBlueprintInstance, new object[] {playerID, blueprintID});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildGhostBlueprint(ICollection<Block> blocks, float3 pos, quaternion rot, uint playerID)
|
||||||
|
{
|
||||||
|
GhostChildUtility.ClearGhostChildren(playerID, entitiesDB, entityFunctions);
|
||||||
|
var bssesopt = entitiesDB.QueryEntityOptional<BoxSelectStateEntityStruct>(new EGID(playerID,
|
||||||
|
BoxSelectExclusiveGroups.BoxSelectVolumeExclusiveGroup));
|
||||||
|
if (!bssesopt)
|
||||||
|
return;
|
||||||
|
foreach (var block in blocks)
|
||||||
|
{
|
||||||
|
GhostChildUtility.BuildGhostChild(in playerID, block.Id, in pos, in rot, entitiesDB,
|
||||||
|
BuildGhostBlueprintFactory, false, bssesopt.Get().buildingDroneReference,
|
||||||
|
FullGameFields._managers.blockLabelResourceManager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Block[] PlaceBlueprintBlocks(uint blueprintID, uint playerID, float3 pos, float3 rot)
|
||||||
|
{ //RobocraftX.CR.MachineEditing.PlaceBlueprintUtility.PlaceBlocksFromSerialisedData
|
||||||
|
var serializationData = clipboardManager.GetSerializationData(blueprintID);
|
||||||
|
var blueprintData = serializationData.blueprintData;
|
||||||
|
blueprintData.dataPos = 0U;
|
||||||
|
uint selectionSize;
|
||||||
|
PositionEntityStruct selectionPosition;
|
||||||
|
RotationEntityStruct selectionRotation;
|
||||||
|
uint version;
|
||||||
|
BoxSelectSerializationUtilities.ReadClipboardHeader(blueprintData, out selectionSize, out selectionPosition, out selectionRotation, out version);
|
||||||
|
((FasterList<EGID>) LocalBlockMap.GetValue(null)).Clear();
|
||||||
|
if (version <= 1U)
|
||||||
|
{
|
||||||
|
uint groupsCount;
|
||||||
|
BoxSelectSerializationUtilities.ReadBlockGroupData(blueprintData, out groupsCount);
|
||||||
|
for (int index = 0; (long) index < (long) groupsCount; ++index)
|
||||||
|
{
|
||||||
|
int nextFilterId = BlockGroupUtility.NextFilterId;
|
||||||
|
entitySerialization.DeserializeNewEntity(new EGID((uint) nextFilterId, BlockGroupExclusiveGroups.BlockGroupEntityGroup), blueprintData, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int nextFilterId1 = BlockGroupUtility.NextFilterId;
|
||||||
|
entityFactory.BuildEntity<BlockGroupEntityDescriptor>(new EGID((uint) nextFilterId1,
|
||||||
|
BlockGroupExclusiveGroups.BlockGroupEntityGroup)).Init(new BlockGroupTransformEntityComponent
|
||||||
|
{
|
||||||
|
blockGroupGridPosition = selectionPosition.position,
|
||||||
|
blockGroupGridRotation = selectionRotation.rotation
|
||||||
|
});
|
||||||
|
var frot = Quaternion.Euler(rot);
|
||||||
|
var grid = new GridRotationStruct {position = pos, rotation = frot};
|
||||||
|
var poss = new PositionEntityStruct {position = pos};
|
||||||
|
var rots = new RotationEntityStruct {rotation = frot};
|
||||||
|
for (int index = 0; (long) index < (long) selectionSize; ++index)
|
||||||
|
BuildBlock.Invoke(null,
|
||||||
|
new object[]
|
||||||
|
{
|
||||||
|
playerID, grid, poss, rots, selectionPosition, selectionRotation, blueprintData,
|
||||||
|
entitySerialization, nextFilterId1
|
||||||
|
});
|
||||||
|
/*
|
||||||
|
uint playerId, in GridRotationStruct ghostParentGrid,
|
||||||
|
in PositionEntityStruct ghostParentPosition, in RotationEntityStruct ghostParentRotation,
|
||||||
|
in PositionEntityStruct selectionPosition, in RotationEntityStruct selectionRotation,
|
||||||
|
ISerializationData serializationData, EntitiesDB entitiesDb,
|
||||||
|
IEntitySerialization entitySerialization, int blockGroupId
|
||||||
|
*/
|
||||||
|
if (globalBlockMap == null)
|
||||||
|
globalBlockMap = FullGameFields._deserialisedBlockMap;
|
||||||
|
var placedBlocks = (FasterList<EGID>) LocalBlockMap.GetValue(null);
|
||||||
|
globalBlockMap.Clear();
|
||||||
|
globalBlockMap.AddRange(placedBlocks);
|
||||||
|
BuildWires.Invoke(null,
|
||||||
|
new object[] {playerID, blueprintData, entitySerialization, entitiesDB, entityFactory});
|
||||||
|
var blocks = new Block[placedBlocks.count];
|
||||||
|
for (int i = 0; i < blocks.Length; i++)
|
||||||
|
blocks[i] = Block.New(placedBlocks[i]);
|
||||||
|
return blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetBlueprintInfo(uint blueprintID, out float3 pos, out quaternion rot, out uint selectionSize)
|
||||||
|
{
|
||||||
|
var serializationData = clipboardManager.GetSerializationData(blueprintID);
|
||||||
|
var blueprintData = serializationData.blueprintData;
|
||||||
|
blueprintData.dataPos = 0U;
|
||||||
|
BoxSelectSerializationUtilities.ReadClipboardHeader(blueprintData, out selectionSize, out var posst,
|
||||||
|
out var rotst, out _);
|
||||||
|
blueprintData.dataPos = 0U; //Just to be sure, it gets reset when it's read anyway
|
||||||
|
pos = posst.position;
|
||||||
|
rot = rotst.rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitBlueprint(uint blueprintID)
|
||||||
|
{
|
||||||
|
clipboardManager.IncrementRefCount(blueprintID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisposeBlueprint(uint blueprintID)
|
||||||
|
{
|
||||||
|
clipboardManager.DecrementRefCount(blueprintID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//GhostChildUtility.BuildGhostChild
|
||||||
|
public Block BuildGhostChild()
|
||||||
|
{
|
||||||
|
var sourceId = new EGID(Player.LocalPlayer.Id, GHOST_BLOCKS_ENABLED.Group);
|
||||||
|
var positionEntityStruct = entitiesDB.QueryEntity<PositionEntityStruct>(sourceId);
|
||||||
|
var rotationEntityStruct = entitiesDB.QueryEntity<RotationEntityStruct>(sourceId);
|
||||||
|
var scalingEntityStruct = entitiesDB.QueryEntity<ScalingEntityStruct>(sourceId);
|
||||||
|
var dbStruct = entitiesDB.QueryEntity<DBEntityStruct>(sourceId);
|
||||||
|
var colliderStruct = entitiesDB.QueryEntity<ColliderAabb>(sourceId);
|
||||||
|
var colorStruct = entitiesDB.QueryEntity<ColourParameterEntityStruct>(sourceId);
|
||||||
|
uint ghostChildBlockId = CommonExclusiveGroups.GetNewGhostChildBlockID();
|
||||||
|
var ghostEntityReference = GhostBlockUtils.GetGhostEntityReference(sourceId.entityID, entitiesDB);
|
||||||
|
var entityInitializer = BuildGhostBlueprintFactory.Build(
|
||||||
|
new EGID(ghostChildBlockId, BoxSelectExclusiveGroups.GhostChildEntitiesExclusiveGroup), /*dbStruct.DBID*/ (uint)BlockIDs.Cube,
|
||||||
|
FullGameFields._managers.blockLabelResourceManager);
|
||||||
|
entityInitializer.Init(dbStruct);
|
||||||
|
entityInitializer.Init(new GFXPrefabEntityStructGPUI(
|
||||||
|
PrefabsID.GetOrAddPrefabID((ushort)entityInitializer.Get<PrefabAssetIDComponent>().prefabAssetID,
|
||||||
|
entitiesDB.QueryEntity<CubeMaterialStruct>(sourceId).materialId, 7,
|
||||||
|
FlippedBlockUtils.IsFlipped(in scalingEntityStruct.scale)), true));
|
||||||
|
entityInitializer.Init(entitiesDB.QueryEntity<CubeMaterialStruct>(sourceId));
|
||||||
|
entityInitializer.Init(new GhostParentEntityStruct
|
||||||
|
{
|
||||||
|
ghostBlockParentEntityReference = ghostEntityReference,
|
||||||
|
ownerMustSerializeOnAdd = false
|
||||||
|
});
|
||||||
|
entityInitializer.Init(colorStruct);
|
||||||
|
entityInitializer.Init(colliderStruct);
|
||||||
|
entityInitializer.Init(new RigidBodyEntityStruct
|
||||||
|
{
|
||||||
|
position = positionEntityStruct.position,
|
||||||
|
rotation = rotationEntityStruct.rotation
|
||||||
|
});
|
||||||
|
entityInitializer.Init(new ScalingEntityStruct
|
||||||
|
{
|
||||||
|
scale = scalingEntityStruct.scale
|
||||||
|
});
|
||||||
|
entityInitializer.Init(new LocalTransformEntityStruct
|
||||||
|
{
|
||||||
|
position = positionEntityStruct.position,
|
||||||
|
rotation = rotationEntityStruct.rotation
|
||||||
|
});
|
||||||
|
entityInitializer.Init(new RotationEntityStruct
|
||||||
|
{
|
||||||
|
rotation = rotationEntityStruct.rotation
|
||||||
|
});
|
||||||
|
entityInitializer.Init(new PositionEntityStruct
|
||||||
|
{
|
||||||
|
position = positionEntityStruct.position
|
||||||
|
});
|
||||||
|
entityInitializer.Init(new SkewComponent
|
||||||
|
{
|
||||||
|
skewMatrix = entitiesDB.QueryEntity<SkewComponent>(sourceId).skewMatrix
|
||||||
|
});
|
||||||
|
entityInitializer.Init(new BlockPlacementInfoStruct
|
||||||
|
{
|
||||||
|
placedByBuildingDrone = entitiesDB
|
||||||
|
.QueryEntityOptional<BoxSelectStateEntityStruct>(new EGID(Player.LocalPlayer.Id,
|
||||||
|
BoxSelectExclusiveGroups.BoxSelectVolumeExclusiveGroup)).Get().buildingDroneReference
|
||||||
|
});
|
||||||
|
entityInitializer.Init(new GridRotationStruct
|
||||||
|
{
|
||||||
|
position = float3.zero,
|
||||||
|
rotation = quaternion.identity
|
||||||
|
});
|
||||||
|
var block = Block.New(entityInitializer.EGID);
|
||||||
|
block.InitData = entityInitializer;
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; } = "TechbloxModdingAPIBlueprintGameEngine";
|
||||||
|
public bool isRemovable { get; } = false;
|
||||||
|
|
||||||
|
[HarmonyPatch]
|
||||||
|
private static class RemoveEnginePatch
|
||||||
|
{
|
||||||
|
public static void Prefix(IEntityFunctions entityFunctions,
|
||||||
|
MachineGraphConnectionEntityFactory machineGraphConnectionEntityFactory)
|
||||||
|
{
|
||||||
|
nativeBlockRemove = entityFunctions.ToNativeRemove<BlockEntityDescriptor>("TBAPI" + nameof(BlueprintEngine));
|
||||||
|
nativeConnectionRemove = entityFunctions.ToNativeRemove<MachineConnectionEntityDescriptor>("TBAPI" + nameof(BlueprintEngine));
|
||||||
|
connectionFactory = machineGraphConnectionEntityFactory;
|
||||||
|
BlueprintEngine.entityFunctions = entityFunctions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodBase TargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.GetDeclaredConstructors(AccessTools.TypeByName("RobocraftX.CR.MachineEditing.RemoveBlockEngine"))[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch]
|
||||||
|
private static class SelectEnginePatch
|
||||||
|
{
|
||||||
|
public static void Prefix(ClipboardSerializationDataResourceManager clipboardSerializationDataResourceManager,
|
||||||
|
IEntitySerialization entitySerialization,
|
||||||
|
IEntityFactory entityFactory)
|
||||||
|
{
|
||||||
|
clipboardManager = clipboardSerializationDataResourceManager;
|
||||||
|
BlueprintEngine.entitySerialization = entitySerialization;
|
||||||
|
BlueprintEngine.entityFactory = entityFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodBase TargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.GetDeclaredConstructors(AccessTools.TypeByName("RobocraftX.CR.MachineEditing.SelectBlockEngine"))[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch]
|
||||||
|
private static class SerializeGhostBlueprintPatch
|
||||||
|
{
|
||||||
|
public static void Postfix(object __instance)
|
||||||
|
{
|
||||||
|
SerializeGhostBlueprintInstance = __instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodBase TargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.GetDeclaredConstructors(SerializeGhostBlueprintType)[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch]
|
||||||
|
private static class BuildGhostBlueprintPatch
|
||||||
|
{
|
||||||
|
public static void Postfix(GhostChildEntityFactory ghostChildEntityFactory)
|
||||||
|
{
|
||||||
|
BuildGhostBlueprintFactory = ghostChildEntityFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodBase TargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.GetDeclaredConstructors(AccessTools.TypeByName("RobocraftX.CR.MachineEditing.BuildGhostChildForMultiblockPickEngine"))[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEntityFactory Factory { get; set; }
|
||||||
|
}
|
||||||
|
}
|
69
TechbloxModdingAPI/Blocks/Engines/MovementEngine.cs
Normal file
69
TechbloxModdingAPI/Blocks/Engines/MovementEngine.cs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.DOTS;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Svelto.ECS.EntityStructs;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
using Unity.Transforms;
|
||||||
|
|
||||||
|
using TechbloxModdingAPI.Engines;
|
||||||
|
using TechbloxModdingAPI.Utility;
|
||||||
|
using TechbloxModdingAPI.Utility.ECS;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Engine which executes block movement actions
|
||||||
|
/// </summary>
|
||||||
|
public class MovementEngine : IApiEngine
|
||||||
|
{
|
||||||
|
public string Name { get; } = "TechbloxModdingAPIMovementGameEngine";
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public bool isRemovable => false;
|
||||||
|
|
||||||
|
public bool IsInGame = false;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
IsInGame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
IsInGame = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// implementations for Movement static class
|
||||||
|
|
||||||
|
internal float3 MoveBlock(Block block, float3 vector)
|
||||||
|
{
|
||||||
|
ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntityOrDefault<PositionEntityStruct>(block);
|
||||||
|
ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntityOrDefault<GridRotationStruct>(block);
|
||||||
|
ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntityOrDefault<LocalTransformEntityStruct>(block);
|
||||||
|
var phyStruct = this.entitiesDB.QueryEntityOptional<DOTSPhysicsEntityStruct>(block);
|
||||||
|
// main (persistent) position
|
||||||
|
posStruct.position = vector;
|
||||||
|
// placement grid position
|
||||||
|
gridStruct.position = vector;
|
||||||
|
// rendered position
|
||||||
|
transStruct.position = vector;
|
||||||
|
// collision position
|
||||||
|
if (phyStruct)
|
||||||
|
{ //It exists
|
||||||
|
FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.Get().dotsEntity, new Translation
|
||||||
|
{
|
||||||
|
Value = posStruct.position
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
entitiesDB.QueryEntityOrDefault<GridConnectionsEntityStruct>(block).areConnectionsAssigned = false;
|
||||||
|
return posStruct.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal float3 GetPosition(Block block)
|
||||||
|
{
|
||||||
|
return entitiesDB.QueryEntityOrDefault<PositionEntityStruct>(block).position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
131
TechbloxModdingAPI/Blocks/Engines/PlacementEngine.cs
Normal file
131
TechbloxModdingAPI/Blocks/Engines/PlacementEngine.cs
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using DataLoader;
|
||||||
|
using Gamecraft.Blocks.BlockGroups;
|
||||||
|
using Gamecraft.Wires;
|
||||||
|
using HarmonyLib;
|
||||||
|
using RobocraftX.Blocks;
|
||||||
|
using RobocraftX.Character;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.CR.MachineEditing.BoxSelect;
|
||||||
|
using RobocraftX.Rendering;
|
||||||
|
using RobocraftX.Rendering.GPUI;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Svelto.ECS.EntityStructs;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
|
||||||
|
using TechbloxModdingAPI.Engines;
|
||||||
|
using TechbloxModdingAPI.Utility;
|
||||||
|
using TechbloxModdingAPI.Utility.ECS;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Engine which executes block placement actions
|
||||||
|
/// </summary>
|
||||||
|
public class PlacementEngine : IApiEngine
|
||||||
|
{
|
||||||
|
public bool IsInGame;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
IsInGame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
IsInGame = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { get; set; }
|
||||||
|
private static BlockEntityFactory _blockEntityFactory; //Injected from PlaceSingleBlockEngine
|
||||||
|
private static IEntityFactory _entityFactory;
|
||||||
|
|
||||||
|
public EntityInitializer PlaceBlock(BlockIDs block, float3 position, Player player, bool autoWire)
|
||||||
|
{ //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
|
||||||
|
return BuildBlock((ushort) block, position, autoWire, (player ?? Player.LocalPlayer).Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EntityInitializer BuildBlock(ushort block, float3 position, bool autoWire, uint playerId)
|
||||||
|
{
|
||||||
|
if (_blockEntityFactory == null)
|
||||||
|
throw new BlockException("The factory is null.");
|
||||||
|
if(!FullGameFields._dataDb.ContainsKey<CubeListData>(block))
|
||||||
|
throw new BlockException("Block with ID " + block + " not found!");
|
||||||
|
//RobocraftX.CR.MachineEditing.PlaceSingleBlockEngine
|
||||||
|
DBEntityStruct dbEntity = new DBEntityStruct {DBID = block};
|
||||||
|
|
||||||
|
EntityInitializer structInitializer = _blockEntityFactory.Build(CommonExclusiveGroups.blockIDGeneratorClient.Next(), block); //The ghost block index is only used for triggers
|
||||||
|
uint prefabAssetID = structInitializer.Has<PrefabAssetIDComponent>()
|
||||||
|
? structInitializer.Get<PrefabAssetIDComponent>().prefabAssetID
|
||||||
|
: throw new BlockException("Prefab asset ID not found!"); //Set by the game
|
||||||
|
uint prefabId = PrefabsID.GetOrAddPrefabID((ushort) prefabAssetID, (byte) BlockMaterial.SteelBodywork, 1, false);
|
||||||
|
structInitializer.Init(new GFXPrefabEntityStructGPUI(prefabId));
|
||||||
|
structInitializer.Init(dbEntity);
|
||||||
|
structInitializer.Init(new PositionEntityStruct {position = position});
|
||||||
|
structInitializer.Init(new RotationEntityStruct {rotation = quaternion.identity});
|
||||||
|
structInitializer.Init(new ScalingEntityStruct {scale = new float3(1, 1, 1)});
|
||||||
|
structInitializer.Init(new GridRotationStruct
|
||||||
|
{
|
||||||
|
position = position,
|
||||||
|
rotation = quaternion.identity
|
||||||
|
});
|
||||||
|
structInitializer.Init(new UniformBlockScaleEntityStruct {scaleFactor = 1});
|
||||||
|
structInitializer.Get<CubeMaterialStruct>().materialId = (byte) BlockMaterial.SteelBodywork;
|
||||||
|
var bssesopt = entitiesDB.QueryEntityOptional<BoxSelectStateEntityStruct>(new EGID(playerId,
|
||||||
|
BoxSelectExclusiveGroups.BoxSelectVolumeExclusiveGroup));
|
||||||
|
if (!bssesopt)
|
||||||
|
throw new BlockException("Invalid player ID specified for block placement");
|
||||||
|
structInitializer.Init(new BlockPlacementInfoStruct
|
||||||
|
{
|
||||||
|
loadedFromDisk = false,
|
||||||
|
placedByBuildingDrone = bssesopt.Get().buildingDroneReference,
|
||||||
|
triggerAutoWiring = autoWire && structInitializer.Has<BlockPortsStruct>()
|
||||||
|
});
|
||||||
|
|
||||||
|
int nextFilterId = BlockGroupUtility.NextFilterId;
|
||||||
|
structInitializer.Init(new BlockGroupEntityComponent
|
||||||
|
{
|
||||||
|
currentBlockGroup = nextFilterId
|
||||||
|
});
|
||||||
|
_entityFactory.BuildEntity<BlockGroupEntityDescriptor>((uint) nextFilterId,
|
||||||
|
BlockGroupExclusiveGroups.BlockGroupEntityGroup)
|
||||||
|
.Init(new BlockGroupTransformEntityComponent
|
||||||
|
{
|
||||||
|
blockGroupGridRotation = quaternion.identity,
|
||||||
|
blockGroupGridPosition = position
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var group in CharacterExclusiveGroups.AllCharacters)
|
||||||
|
{
|
||||||
|
EGID playerEGID = new EGID(playerId, group);
|
||||||
|
if (!entitiesDB.TryQueryEntitiesAndIndex<PickedBlockExtraDataStruct>(playerEGID, out uint index,
|
||||||
|
out var array)) continue;
|
||||||
|
ref PickedBlockExtraDataStruct pickedBlock = ref array[index];
|
||||||
|
pickedBlock.placedBlockEntityID = structInitializer.EGID;
|
||||||
|
pickedBlock.placedBlockWasAPickedBlock = false;
|
||||||
|
}
|
||||||
|
return structInitializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name => "TechbloxModdingAPIPlacementGameEngine";
|
||||||
|
|
||||||
|
public bool isRemovable => false;
|
||||||
|
|
||||||
|
[HarmonyPatch]
|
||||||
|
class FactoryObtainerPatch
|
||||||
|
{
|
||||||
|
static void Postfix(BlockEntityFactory blockEntityFactory, IEntityFactory entityFactory)
|
||||||
|
{
|
||||||
|
_blockEntityFactory = blockEntityFactory;
|
||||||
|
_entityFactory = entityFactory;
|
||||||
|
Logging.MetaDebugLog("Block entity factory injected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static MethodBase TargetMethod(Harmony instance)
|
||||||
|
{
|
||||||
|
return AccessTools.TypeByName("RobocraftX.CR.MachineEditing.PlaceSingleBlockEngine").GetConstructors()[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
86
TechbloxModdingAPI/Blocks/Engines/RemovalEngine.cs
Normal file
86
TechbloxModdingAPI/Blocks/Engines/RemovalEngine.cs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using Gamecraft.Blocks.BlockGroups;
|
||||||
|
using HarmonyLib;
|
||||||
|
using RobocraftX.Blocks;
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.GroupTags;
|
||||||
|
using RobocraftX.StateSync;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Svelto.ECS.Native;
|
||||||
|
using Techblox.Blocks.Connections;
|
||||||
|
using Unity.Collections;
|
||||||
|
using Unity.Jobs;
|
||||||
|
using Allocator = Unity.Collections.Allocator;
|
||||||
|
|
||||||
|
using TechbloxModdingAPI.Engines;
|
||||||
|
using TechbloxModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
{
|
||||||
|
public class RemovalEngine : IApiEngine, IDeterministicTimeStopped
|
||||||
|
{
|
||||||
|
private static IEntityFunctions _entityFunctions;
|
||||||
|
private static MachineGraphConnectionEntityFactory _connectionFactory;
|
||||||
|
private NativeHashSet<ulong> removedConnections;
|
||||||
|
|
||||||
|
public bool RemoveBlock(EGID target)
|
||||||
|
{
|
||||||
|
if (!entitiesDB.Exists<MachineGraphConnectionsEntityStruct>(target))
|
||||||
|
return false;
|
||||||
|
using var connStructMapper =
|
||||||
|
entitiesDB.QueryNativeMappedEntities<MachineGraphConnectionsEntityStruct>(GroupTag<BLOCK_TAG>.Groups,
|
||||||
|
Svelto.Common.Allocator.Temp);
|
||||||
|
if (entitiesDB.TryQueryNativeMappedEntities<MachineConnectionComponent>(
|
||||||
|
ConnectionsExclusiveGroups.MACHINE_CONNECTION_GROUP, out var mapper))
|
||||||
|
{
|
||||||
|
BlockGroupUtility.RemoveBlockConnections(target, removedConnections, _connectionFactory,
|
||||||
|
connStructMapper, mapper, entitiesDB.GetEntityReferenceMap(), _entityFunctions);
|
||||||
|
}
|
||||||
|
|
||||||
|
_entityFunctions.RemoveEntity<BlockEntityDescriptor>(target);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
removedConnections = new(2000, Allocator.Persistent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { get; set; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
removedConnections.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name => "TechbloxModdingAPIRemovalGameEngine";
|
||||||
|
public string name => Name;
|
||||||
|
|
||||||
|
public bool isRemovable => false;
|
||||||
|
|
||||||
|
[HarmonyPatch]
|
||||||
|
class FactoryObtainerPatch
|
||||||
|
{
|
||||||
|
static void Postfix(IEntityFunctions entityFunctions,
|
||||||
|
MachineGraphConnectionEntityFactory machineGraphConnectionEntityFactory)
|
||||||
|
{
|
||||||
|
_entityFunctions = entityFunctions;
|
||||||
|
_connectionFactory = machineGraphConnectionEntityFactory;
|
||||||
|
Logging.MetaDebugLog("Requirements injected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static MethodBase TargetMethod(Harmony instance)
|
||||||
|
{
|
||||||
|
return AccessTools.TypeByName("RobocraftX.CR.MachineEditing.RemoveBlockEngine").GetConstructors()[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JobHandle DeterministicStep(in float deltaTime, JobHandle inputDeps)
|
||||||
|
{
|
||||||
|
if (removedConnections.IsCreated)
|
||||||
|
removedConnections.Clear();
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
76
TechbloxModdingAPI/Blocks/Engines/RotationEngine.cs
Normal file
76
TechbloxModdingAPI/Blocks/Engines/RotationEngine.cs
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using RobocraftX.DOTS;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Svelto.ECS.EntityStructs;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
using TechbloxModdingAPI.Engines;
|
||||||
|
using TechbloxModdingAPI.Utility;
|
||||||
|
using TechbloxModdingAPI.Utility.ECS;
|
||||||
|
|
||||||
|
namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Engine which executes block movement actions
|
||||||
|
/// </summary>
|
||||||
|
public class RotationEngine : IApiEngine
|
||||||
|
{
|
||||||
|
public string Name { get; } = "TechbloxModdingAPIRotationGameEngine";
|
||||||
|
|
||||||
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public bool isRemovable => false;
|
||||||
|
|
||||||
|
public bool IsInGame = false;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
IsInGame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Ready()
|
||||||
|
{
|
||||||
|
IsInGame = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// implementations for Rotation static class
|
||||||
|
|
||||||
|
internal float3 RotateBlock(Block block, Vector3 vector)
|
||||||
|
{
|
||||||
|
ref RotationEntityStruct rotStruct = ref this.entitiesDB.QueryEntityOrDefault<RotationEntityStruct>(block);
|
||||||
|
ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntityOrDefault<GridRotationStruct>(block);
|
||||||
|
ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntityOrDefault<LocalTransformEntityStruct>(block);
|
||||||
|
var phyStruct = this.entitiesDB.QueryEntityOptional<DOTSPhysicsEntityStruct>(block);
|
||||||
|
// main (persistent) rotation
|
||||||
|
Quaternion newRotation = rotStruct.rotation;
|
||||||
|
newRotation.eulerAngles = vector;
|
||||||
|
rotStruct.rotation = newRotation;
|
||||||
|
// placement grid rotation
|
||||||
|
gridStruct.rotation = newRotation;
|
||||||
|
// rendered rotation
|
||||||
|
transStruct.rotation = newRotation;
|
||||||
|
// collision rotation
|
||||||
|
if (phyStruct)
|
||||||
|
{ //It exists
|
||||||
|
FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.Get().dotsEntity,
|
||||||
|
new Unity.Transforms.Rotation
|
||||||
|
{
|
||||||
|
Value = rotStruct.rotation
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Connections probably need to be assigned (maybe)
|
||||||
|
// They are assigned during machine processing anyway
|
||||||
|
entitiesDB.QueryEntityOrDefault<GridConnectionsEntityStruct>(block).areConnectionsAssigned = false;
|
||||||
|
return ((Quaternion)rotStruct.rotation).eulerAngles;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal float3 GetRotation(Block block)
|
||||||
|
{
|
||||||
|
ref RotationEntityStruct rotStruct = ref entitiesDB.QueryEntityOrDefault<RotationEntityStruct>(block);
|
||||||
|
return ((Quaternion) rotStruct.rotation).eulerAngles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue