Compare commits
No commits in common. "master" and "preview" have entirely different histories.
68 changed files with 2513 additions and 4867 deletions
|
@ -5,7 +5,7 @@ import re
|
||||||
# this assumes a mostly semver-complient version number
|
# this assumes a mostly semver-complient version number
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(description="Increment TechbloxModdingAPI version")
|
parser = argparse.ArgumentParser(description="Increment GamecraftModdingAPI version")
|
||||||
parser.add_argument('version', metavar="VN", type=str, help="The version number to increment, or the index of the number (zero-indexed).")
|
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()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
@ -28,12 +28,12 @@ if __name__ == "__main__":
|
||||||
old_version = ""
|
old_version = ""
|
||||||
new_version = ""
|
new_version = ""
|
||||||
|
|
||||||
with open("../TechbloxModdingAPI/TechbloxModdingAPI.csproj", "r") as xmlFile:
|
with open("../GamecraftModdingAPI/GamecraftModdingAPI.csproj", "r") as xmlFile:
|
||||||
print("Parsing TechbloxModdingAPI.csproj")
|
print("Parsing GamecraftModdingAPI.csproj")
|
||||||
fileStr = xmlFile.read()
|
fileStr = xmlFile.read()
|
||||||
versionMatch = re.search(r"<Version>(.+)</Version>", fileStr)
|
versionMatch = re.search(r"<Version>(.+)</Version>", fileStr)
|
||||||
if versionMatch is None:
|
if versionMatch is None:
|
||||||
print("Unable to find version number in TechbloxModdingAPI.csproj")
|
print("Unable to find version number in GamecraftModdingAPI.csproj")
|
||||||
exit(1)
|
exit(1)
|
||||||
old_version = versionMatch.group(1)
|
old_version = versionMatch.group(1)
|
||||||
versionList = old_version.split(".")
|
versionList = old_version.split(".")
|
||||||
|
@ -53,7 +53,7 @@ if __name__ == "__main__":
|
||||||
print(new_version)
|
print(new_version)
|
||||||
newFileContents = fileStr.replace("<Version>"+old_version+"</Version>", "<Version>"+new_version+"</Version>")
|
newFileContents = fileStr.replace("<Version>"+old_version+"</Version>", "<Version>"+new_version+"</Version>")
|
||||||
|
|
||||||
with open("../TechbloxModdingAPI/TechbloxModdingAPI.csproj", "w") as xmlFile:
|
with open("../GamecraftModdingAPI/GamecraftModdingAPI.csproj", "w") as xmlFile:
|
||||||
print("Writing new version to project file")
|
print("Writing new version to project file")
|
||||||
xmlFile.write(newFileContents)
|
xmlFile.write(newFileContents)
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ from pathlib import Path, PurePath
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
|
|
||||||
DLL_EXCLUSIONS_REGEX = r"(System|Microsoft|Mono|IronPython|DiscordRPC|IllusionInjector|IllusionPlugin|netstandard)\."
|
DLL_EXCLUSIONS_REGEX = r"(System|Microsoft|Mono|IronPython|DiscordRPC)\."
|
||||||
|
|
||||||
def getAssemblyReferences(path):
|
def getAssemblyReferences(path):
|
||||||
asmDir = Path(path)
|
asmDir = Path(path)
|
||||||
|
@ -15,12 +15,10 @@ def getAssemblyReferences(path):
|
||||||
addedPath = "../"
|
addedPath = "../"
|
||||||
asmDir = Path(addedPath + path)
|
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)) is None and str(child).lower().endswith(".dll"):
|
if child.is_file() and re.search(DLL_EXCLUSIONS_REGEX, str(child), re.I) is None and str(child).lower().endswith(".dll"):
|
||||||
childstr = str(child)
|
childstr = str(child)
|
||||||
childstr = os.path.relpath(childstr, addedPath).replace("\\", "/")
|
childstr = os.path.relpath(childstr, addedPath).replace("\\", "/")
|
||||||
result.append(childstr)
|
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):
|
||||||
|
@ -41,7 +39,7 @@ if __name__ == "__main__":
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
print("Building Assembly references")
|
print("Building Assembly references")
|
||||||
asmXml = buildReferencesXml("../ref_TB/Techblox_Data/Managed")
|
asmXml = buildReferencesXml("../ref_preview/TechbloxPreview_Data/Managed")
|
||||||
# print(asmXml)
|
# print(asmXml)
|
||||||
|
|
||||||
with open("../TechbloxModdingAPI/TechbloxModdingAPI.csproj", "r") as xmlFile:
|
with open("../TechbloxModdingAPI/TechbloxModdingAPI.csproj", "r") as xmlFile:
|
||||||
|
@ -53,7 +51,7 @@ 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() - 1] + "\n" + asmXml + "\n" + fileStr[depsEnd.end() + 1:]
|
newFileStr = fileStr[:depsStart.start()] + "\n" + asmXml + "\n" + fileStr[depsEnd.end() + 1:]
|
||||||
with open("../TechbloxModdingAPI/TechbloxModdingAPI.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)
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><configuration>
|
|
||||||
<runtime>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="mscorlib" publicKeyToken="b77a5c561934e089" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
</runtime>
|
|
||||||
</configuration>
|
|
|
@ -8,6 +8,7 @@ using System.Reflection;
|
||||||
using Gamecraft.Tweaks;
|
using Gamecraft.Tweaks;
|
||||||
using RobocraftX.Common;
|
using RobocraftX.Common;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
|
using Techblox.EngineBlock;
|
||||||
|
|
||||||
namespace CodeGenerator
|
namespace CodeGenerator
|
||||||
{
|
{
|
||||||
|
@ -22,7 +23,7 @@ namespace CodeGenerator
|
||||||
group = GetGroup(name) + "_BLOCK_BUILD_GROUP";
|
group = GetGroup(name) + "_BLOCK_BUILD_GROUP";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!group.Contains('.'))
|
if (!group.Contains("."))
|
||||||
group = "CommonExclusiveGroups." + group;
|
group = "CommonExclusiveGroups." + group;
|
||||||
|
|
||||||
var codeUnit = new CodeCompileUnit();
|
var codeUnit = new CodeCompileUnit();
|
||||||
|
@ -67,7 +68,7 @@ namespace CodeGenerator
|
||||||
codeUnit.Namespaces.Add(ns);
|
codeUnit.Namespaces.Add(ns);
|
||||||
|
|
||||||
var provider = CodeDomProvider.CreateProvider("CSharp");
|
var provider = CodeDomProvider.CreateProvider("CSharp");
|
||||||
var path = $@"../../../../TechbloxModdingAPI/Blocks/{name}.cs";
|
var path = $@"..\..\..\TechbloxModdingAPI\Blocks\{name}.cs";
|
||||||
using (var sw = new StreamWriter(path))
|
using (var sw = new StreamWriter(path))
|
||||||
{
|
{
|
||||||
provider.GenerateCodeFromCompileUnit(codeUnit, sw, new CodeGeneratorOptions {BracingStyle = "C"});
|
provider.GenerateCodeFromCompileUnit(codeUnit, sw, new CodeGeneratorOptions {BracingStyle = "C"});
|
||||||
|
@ -96,8 +97,6 @@ namespace CodeGenerator
|
||||||
{
|
{
|
||||||
if (!typeof(IEntityComponent).IsAssignableFrom(type))
|
if (!typeof(IEntityComponent).IsAssignableFrom(type))
|
||||||
throw new ArgumentException("Type must be an entity component");
|
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())
|
foreach (var field in type.GetFields())
|
||||||
{
|
{
|
||||||
var attr = field.GetCustomAttribute<TweakableStatAttribute>();
|
var attr = field.GetCustomAttribute<TweakableStatAttribute>();
|
||||||
|
@ -109,20 +108,10 @@ namespace CodeGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
propName = char.ToUpper(propName[0]) + propName.Substring(1);
|
propName = char.ToUpper(propName[0]) + propName.Substring(1);
|
||||||
var getStruct = new CodeMethodInvokeExpression(
|
var structFieldReference = new CodeFieldReferenceExpression(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"),
|
new CodeMethodReferenceExpression(new CodeSnippetExpression("BlockEngine"),
|
||||||
"GetBlockInfo"),
|
"GetBlockInfo", new CodeTypeReference(type)),
|
||||||
new CodeThisReferenceExpression(), reflectedType, new CodePrimitiveExpression(field.Name)));
|
new CodeThisReferenceExpression()), 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
|
cl.Members.Add(new CodeMemberProperty
|
||||||
{
|
{
|
||||||
Name = propName,
|
Name = propName,
|
||||||
|
@ -130,23 +119,18 @@ namespace CodeGenerator
|
||||||
HasSet = true,
|
HasSet = true,
|
||||||
GetStatements =
|
GetStatements =
|
||||||
{
|
{
|
||||||
new CodeMethodReturnStatement(reflection ? reflectedGet : structFieldReference)
|
new CodeMethodReturnStatement(structFieldReference)
|
||||||
},
|
},
|
||||||
SetStatements =
|
SetStatements =
|
||||||
{
|
{
|
||||||
reflection
|
new CodeAssignStatement(structFieldReference, new CodePropertySetValueReferenceExpression())
|
||||||
? (CodeStatement)new CodeExpressionStatement(reflectedSet)
|
|
||||||
: new CodeAssignStatement(structFieldReference, new CodePropertySetValueReferenceExpression())
|
|
||||||
},
|
},
|
||||||
Type = new CodeTypeReference(field.FieldType),
|
Type = new CodeTypeReference(field.FieldType),
|
||||||
Attributes = MemberAttributes.Public | MemberAttributes.Final,
|
Attributes = MemberAttributes.Public | MemberAttributes.Final,
|
||||||
Comments =
|
Comments =
|
||||||
{
|
{
|
||||||
_start,
|
_start, new CodeCommentStatement($"Gets or sets the {baseClass}'s {propName} property." +
|
||||||
new CodeCommentStatement($"Gets or sets the {baseClass}'s {propName} property." +
|
$" {(attr != null ? "Tweakable stat." : "May not be saved.")}", true), _end
|
||||||
$" {(attr != null ? "Tweakable stat." : "May not be saved.")}",
|
|
||||||
true),
|
|
||||||
_end
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,12 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using HarmonyLib;
|
|
||||||
using RobocraftX.Blocks;
|
using RobocraftX.Blocks;
|
||||||
using RobocraftX.Common;
|
|
||||||
using RobocraftX.GroupTags;
|
|
||||||
using RobocraftX.PilotSeat;
|
using RobocraftX.PilotSeat;
|
||||||
using Svelto.ECS;
|
|
||||||
using Techblox.EngineBlock;
|
using Techblox.EngineBlock;
|
||||||
using Techblox.ServoBlocksServer;
|
|
||||||
using Techblox.WheelRigBlock;
|
using Techblox.WheelRigBlock;
|
||||||
|
|
||||||
namespace CodeGenerator
|
namespace CodeGenerator
|
||||||
|
@ -14,17 +9,12 @@ namespace CodeGenerator
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
|
||||||
GenerateBlockClasses();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void GenerateBlockClasses()
|
|
||||||
{
|
{
|
||||||
var bcg = new BlockClassGenerator();
|
var bcg = new BlockClassGenerator();
|
||||||
bcg.Generate("Engine", null, new Dictionary<string, string>
|
bcg.Generate("Engine", null, new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
{ "engineOn", "On" }
|
{ "engineOn", "On" }
|
||||||
}, AccessTools.TypeByName("Techblox.EngineBlock.EngineBlockComponent"), // Simulation time properties
|
}, typeof(EngineBlockComponent), // Simulation time properties
|
||||||
typeof(EngineBlockTweakableComponent), typeof(EngineBlockReadonlyComponent));
|
typeof(EngineBlockTweakableComponent), typeof(EngineBlockReadonlyComponent));
|
||||||
bcg.Generate("DampedSpring", "DAMPEDSPRING_BLOCK_GROUP", new Dictionary<string, string>
|
bcg.Generate("DampedSpring", "DAMPEDSPRING_BLOCK_GROUP", new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
|
@ -32,7 +22,7 @@ namespace CodeGenerator
|
||||||
},
|
},
|
||||||
typeof(TweakableJointDampingComponent), typeof(DampedSpringReadOnlyStruct));
|
typeof(TweakableJointDampingComponent), typeof(DampedSpringReadOnlyStruct));
|
||||||
bcg.Generate("LogicGate", "LOGIC_BLOCK_GROUP");
|
bcg.Generate("LogicGate", "LOGIC_BLOCK_GROUP");
|
||||||
bcg.Generate("Servo", types: typeof(ServoReadOnlyTweakableComponent), renames: new Dictionary<string, string>
|
bcg.Generate("Servo", types: typeof(ServoReadOnlyStruct), renames: new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
{"minDeviation", "MinimumAngle"},
|
{"minDeviation", "MinimumAngle"},
|
||||||
{"maxDeviation", "MaximumAngle"},
|
{"maxDeviation", "MaximumAngle"},
|
||||||
|
@ -47,7 +37,6 @@ namespace CodeGenerator
|
||||||
{"pistonVelocity", "MaximumForce"}
|
{"pistonVelocity", "MaximumForce"}
|
||||||
}, typeof(PistonReadOnlyStruct));
|
}, typeof(PistonReadOnlyStruct));
|
||||||
bcg.Generate("Motor", null, null, typeof(MotorReadOnlyStruct));
|
bcg.Generate("Motor", null, null, typeof(MotorReadOnlyStruct));
|
||||||
//bcg.Generate("ObjectID", "ObjectIDBlockExclusiveGroups.OBJECT_ID_BLOCK_GROUP", null, typeof(ObjectIDTweakableComponent));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
35
CodeGenerator/Properties/AssemblyInfo.cs
Normal file
35
CodeGenerator/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("CodeGenerator")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("CodeGenerator")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © ExMods 2021")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("0EBB6400-95A7-4A3D-B2ED-BF31E364CC10")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -1,4 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<packages>
|
|
||||||
<package id="Lib.Harmony" version="2.2.0" targetFramework="net472" />
|
|
||||||
</packages>
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,25 +0,0 @@
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using Mono.Cecil;
|
|
||||||
|
|
||||||
Console.WriteLine("Starting assembly editing...");
|
|
||||||
var fileRegex =
|
|
||||||
new Regex(".*(Techblox|Gamecraft|RobocraftX|FullGame|RobocraftECS|DataLoader|RCX|GameState|Svelto\\.ECS)[^/]*(\\.dll)");
|
|
||||||
foreach (var file in Directory.EnumerateFiles(@"../../../../../ref/Techblox_Data/Managed"))
|
|
||||||
{
|
|
||||||
if (!fileRegex.IsMatch(file)) continue;
|
|
||||||
Console.WriteLine(file);
|
|
||||||
ProcessAssembly(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcessAssembly(string path)
|
|
||||||
{
|
|
||||||
using var mod = ModuleDefinition.ReadModule(path, new(ReadingMode.Immediate) { ReadWrite = true });
|
|
||||||
foreach (var typeDefinition in mod.Types)
|
|
||||||
{
|
|
||||||
typeDefinition.IsPublic = true;
|
|
||||||
foreach (var method in typeDefinition.Methods) method.IsPublic = true;
|
|
||||||
foreach (var field in typeDefinition.Fields) field.IsPublic = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
mod.Write();
|
|
||||||
}
|
|
|
@ -7,8 +7,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TechbloxModdingAPI", "Techb
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeGenerator", "CodeGenerator\CodeGenerator.csproj", "{0EBB6400-95A7-4A3D-B2ED-BF31E364CC10}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeGenerator", "CodeGenerator\CodeGenerator.csproj", "{0EBB6400-95A7-4A3D-B2ED-BF31E364CC10}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MakeEverythingPublicInGame", "MakeEverythingPublicInGame\MakeEverythingPublicInGame.csproj", "{391A3107-E5C6-4A04-9467-6D868AA9A8B4}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -28,12 +26,6 @@ Global
|
||||||
{0EBB6400-95A7-4A3D-B2ED-BF31E364CC10}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
|
||||||
{0EBB6400-95A7-4A3D-B2ED-BF31E364CC10}.Test|Any CPU.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
@ -2,7 +2,6 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using Svelto.Tasks;
|
using Svelto.Tasks;
|
||||||
using Techblox.Anticheat.Client;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.App
|
namespace TechbloxModdingAPI.App
|
||||||
{
|
{
|
||||||
|
@ -22,8 +21,7 @@ namespace TechbloxModdingAPI.App
|
||||||
harmony.Patch(AccessTools.Method(type, "StartProtectedSession"), new HarmonyMethod(((AntiAnticheatDelegate) 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(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.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("Techblox.Anticheat.Client.Engines.ShowFeedbackDialogEngine: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() => false;
|
||||||
|
|
|
@ -114,6 +114,11 @@ namespace TechbloxModdingAPI.App
|
||||||
popup.SecondButton();
|
popup.SecondButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void CloseBetaPopup()
|
||||||
|
{
|
||||||
|
Game.menuEngine.CloseBetaPopup();
|
||||||
|
}
|
||||||
|
|
||||||
internal static void Init()
|
internal static void Init()
|
||||||
{
|
{
|
||||||
// this would have been so much simpler if this didn't involve a bunch of internal fields & classes
|
// this would have been so much simpler if this didn't involve a bunch of internal fields & classes
|
||||||
|
|
|
@ -27,12 +27,14 @@ namespace TechbloxModdingAPI.App
|
||||||
|
|
||||||
public JobHandle OnInitializeTimeRunningMode(JobHandle inputDeps)
|
public JobHandle OnInitializeTimeRunningMode(JobHandle inputDeps)
|
||||||
{
|
{
|
||||||
|
Console.WriteLine("Init time running mode");
|
||||||
SimulationMode.Invoke(this, new GameEventArgs { GameName = "", GamePath = "" }); // TODO
|
SimulationMode.Invoke(this, new GameEventArgs { GameName = "", GamePath = "" }); // TODO
|
||||||
return inputDeps;
|
return inputDeps;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JobHandle OnInitializeTimeStoppedMode(JobHandle inputDeps)
|
public JobHandle OnInitializeTimeStoppedMode(JobHandle inputDeps)
|
||||||
{
|
{
|
||||||
|
Console.WriteLine("Init time stopped mode");
|
||||||
BuildMode.Invoke(this, new GameEventArgs { GameName = "", GamePath = "" });
|
BuildMode.Invoke(this, new GameEventArgs { GameName = "", GamePath = "" });
|
||||||
return inputDeps;
|
return inputDeps;
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,19 +140,18 @@ namespace TechbloxModdingAPI.App
|
||||||
{
|
{
|
||||||
var allBlocks = entitiesDB.QueryEntities<BlockTagEntityStruct>();
|
var allBlocks = entitiesDB.QueryEntities<BlockTagEntityStruct>();
|
||||||
List<EGID> blockEGIDs = new List<EGID>();
|
List<EGID> blockEGIDs = new List<EGID>();
|
||||||
foreach (var ((_, ids, count), group) in allBlocks)
|
foreach (var (blocks, _) in allBlocks)
|
||||||
{
|
{
|
||||||
|
var (buffer, count) = blocks.ToBuffer();
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var id = new EGID(ids[i], group);
|
|
||||||
uint dbid;
|
uint dbid;
|
||||||
if (filter == BlockIDs.Invalid)
|
if (filter == BlockIDs.Invalid)
|
||||||
dbid = (uint)filter;
|
dbid = (uint)filter;
|
||||||
else
|
else
|
||||||
dbid = entitiesDB.QueryEntity<DBEntityStruct>(id).DBID;
|
dbid = entitiesDB.QueryEntity<DBEntityStruct>(buffer[i].ID).DBID;
|
||||||
var ownership = entitiesDB.QueryEntity<BlockOwnershipComponent>(id).BlockOwnership;
|
if (dbid == (ulong)filter)
|
||||||
if ((ownership & BlockOwnership.User) != 0 && dbid == (ulong)filter)
|
blockEGIDs.Add(buffer[i].ID);
|
||||||
blockEGIDs.Add(id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,12 +55,13 @@ namespace TechbloxModdingAPI.App
|
||||||
|
|
||||||
public Game[] GetMyGames()
|
public Game[] GetMyGames()
|
||||||
{
|
{
|
||||||
var (mgsevs, count) = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames);
|
EntityCollection<MyGameDataEntityStruct> mgsevs = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames);
|
||||||
Game[] games = new Game[count];
|
var mgsevsB = mgsevs.ToBuffer().buffer;
|
||||||
for (int i = 0; i < count; i++)
|
Game[] games = new Game[mgsevs.count];
|
||||||
|
for (int i = 0; i < mgsevs.count; i++)
|
||||||
{
|
{
|
||||||
Utility.Logging.MetaDebugLog($"Found game named {mgsevs[i].GameName}");
|
Utility.Logging.MetaDebugLog($"Found game named {mgsevsB[i].GameName}");
|
||||||
games[i] = new Game(mgsevs[i].ID);
|
games[i] = new Game(mgsevsB[i].ID);
|
||||||
}
|
}
|
||||||
return games;
|
return games;
|
||||||
}
|
}
|
||||||
|
@ -83,13 +84,14 @@ namespace TechbloxModdingAPI.App
|
||||||
|
|
||||||
public uint HighestID()
|
public uint HighestID()
|
||||||
{
|
{
|
||||||
var (games, count) = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames);
|
EntityCollection<MyGameDataEntityStruct> games = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames);
|
||||||
|
var gamesB = games.ToBuffer().buffer;
|
||||||
uint max = 0;
|
uint max = 0;
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < games.count; i++)
|
||||||
{
|
{
|
||||||
if (games[i].ID.entityID > max)
|
if (gamesB[i].ID.entityID > max)
|
||||||
{
|
{
|
||||||
max = games[i].ID.entityID;
|
max = gamesB[i].ID.entityID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return max;
|
return max;
|
||||||
|
@ -154,6 +156,16 @@ namespace TechbloxModdingAPI.App
|
||||||
{
|
{
|
||||||
return ref entitiesDB.QueryEntity<T>(id);
|
return ref entitiesDB.QueryEntity<T>(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void CloseBetaPopup()
|
||||||
|
{
|
||||||
|
var (buffer, count) = entitiesDB.QueryEntities<TogglePanelButtonEntityViewStruct>(ExclusiveGroup.Search("BetaPopup"));
|
||||||
|
for (int index = 0; index < count; ++index)
|
||||||
|
{
|
||||||
|
entitiesDB.QueryEntity<GUIEntityViewStruct>(buffer[index].TogglePanelButtonComponent.targetPanel)
|
||||||
|
.guiRoot.enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class MyGameDataEntityDescriptor_DamnItFJWhyDidYouMakeThisInternal : GenericEntityDescriptor<MyGameDataEntityStruct> { }
|
internal class MyGameDataEntityDescriptor_DamnItFJWhyDidYouMakeThisInternal : GenericEntityDescriptor<MyGameDataEntityStruct> { }
|
||||||
|
|
|
@ -11,7 +11,8 @@ using Unity.Mathematics;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using RobocraftX.PilotSeat;
|
using RobocraftX.PilotSeat;
|
||||||
using RobocraftX.Rendering;
|
using RobocraftX.Rendering;
|
||||||
using Techblox.BlockLabelsServer;
|
using Techblox.BlockLabels;
|
||||||
|
|
||||||
using TechbloxModdingAPI.Blocks;
|
using TechbloxModdingAPI.Blocks;
|
||||||
using TechbloxModdingAPI.Blocks.Engines;
|
using TechbloxModdingAPI.Blocks.Engines;
|
||||||
using TechbloxModdingAPI.Tests;
|
using TechbloxModdingAPI.Tests;
|
||||||
|
@ -45,10 +46,12 @@ namespace TechbloxModdingAPI
|
||||||
/// <param name="position">The block's position - default block size is 0.2</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="autoWire">Whether the block should be auto-wired (if functional)</param>
|
||||||
/// <param name="player">The player who placed the block</param>
|
/// <param name="player">The player who placed the block</param>
|
||||||
|
/// <param name="force"></param>
|
||||||
/// <returns>The placed block or null if failed</returns>
|
/// <returns>The placed block or null if failed</returns>
|
||||||
public static Block PlaceNew(BlockIDs block, float3 position, bool autoWire = false, Player player = null)
|
public static Block PlaceNew(BlockIDs block, float3 position, bool autoWire = false, Player player = null,
|
||||||
|
bool force = false)
|
||||||
{
|
{
|
||||||
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
|
if (PlacementEngine.IsInGame && (GameState.IsBuildMode() || force))
|
||||||
{
|
{
|
||||||
var initializer = PlacementEngine.PlaceBlock(block, position, player, autoWire);
|
var initializer = PlacementEngine.PlaceBlock(block, position, player, autoWire);
|
||||||
var egid = initializer.EGID;
|
var egid = initializer.EGID;
|
||||||
|
@ -67,7 +70,7 @@ namespace TechbloxModdingAPI
|
||||||
/// <returns>The block object or null if doesn't exist</returns>
|
/// <returns>The block object or null if doesn't exist</returns>
|
||||||
public static Block GetLastPlacedBlock()
|
public static Block GetLastPlacedBlock()
|
||||||
{
|
{
|
||||||
uint lastBlockID = CommonExclusiveGroups.blockIDGeneratorClient.Peek() - 1;
|
uint lastBlockID = (uint) AccessTools.Field(typeof(CommonExclusiveGroups), "_nextBlockEntityID").GetValue(null) - 1;
|
||||||
EGID? egid = BlockEngine.FindBlockEGID(lastBlockID);
|
EGID? egid = BlockEngine.FindBlockEGID(lastBlockID);
|
||||||
return egid.HasValue ? New(egid.Value) : null;
|
return egid.HasValue ? New(egid.Value) : null;
|
||||||
}
|
}
|
||||||
|
@ -160,10 +163,11 @@ namespace TechbloxModdingAPI
|
||||||
/// <param name="position">The block's position (a block is 0.2 wide in terms of position)</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="autoWire">Whether the block should be auto-wired (if functional)</param>
|
||||||
/// <param name="player">The player who placed the block</param>
|
/// <param name="player">The player who placed the block</param>
|
||||||
public Block(BlockIDs type, float3 position, bool autoWire = false, Player player = null)
|
/// <param name="force">Place even if not in build mode</param>
|
||||||
|
public Block(BlockIDs type, float3 position, bool autoWire = false, Player player = null, bool force = false)
|
||||||
: base(block =>
|
: base(block =>
|
||||||
{
|
{
|
||||||
if (!PlacementEngine.IsInGame || !GameState.IsBuildMode())
|
if (!PlacementEngine.IsInGame || !GameState.IsBuildMode() && !force)
|
||||||
throw new BlockException("Blocks can only be placed in build mode.");
|
throw new BlockException("Blocks can only be placed in build mode.");
|
||||||
var initializer = PlacementEngine.PlaceBlock(type, position, player, autoWire);
|
var initializer = PlacementEngine.PlaceBlock(type, position, player, autoWire);
|
||||||
block.InitData = initializer;
|
block.InitData = initializer;
|
||||||
|
@ -288,7 +292,6 @@ namespace TechbloxModdingAPI
|
||||||
color.indexInPalette = value.Index;
|
color.indexInPalette = value.Index;
|
||||||
color.hasNetworkChange = true;
|
color.hasNetworkChange = true;
|
||||||
color.paletteColour = BlockEngine.ConvertBlockColor(color.indexInPalette); //Setting to 255 results in black
|
color.paletteColour = BlockEngine.ConvertBlockColor(color.indexInPalette); //Setting to 255 results in black
|
||||||
BlockEngine.UpdateBlockColor(Id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,15 +343,9 @@ namespace TechbloxModdingAPI
|
||||||
[TestValue(null)]
|
[TestValue(null)]
|
||||||
public string Label
|
public string Label
|
||||||
{
|
{
|
||||||
get
|
get => BlockEngine.GetBlockInfo<LabelResourceIDComponent>(this).ToString(); //TODO: Block labels
|
||||||
{
|
|
||||||
var opt = BlockEngine.GetBlockInfoOptional<LabelResourceIDComponent>(this);
|
|
||||||
return opt ? FullGameFields._managers.blockLabelResourceManager.GetText(opt.Get().instanceID) : null;
|
|
||||||
}
|
|
||||||
set
|
set
|
||||||
{
|
{ //TODO
|
||||||
var opt = BlockEngine.GetBlockInfoOptional<LabelResourceIDComponent>(this);
|
|
||||||
if (opt) FullGameFields._managers.blockLabelResourceManager.SetText(opt.Get().instanceID, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,12 +363,8 @@ namespace TechbloxModdingAPI
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (blockGroup != null) return blockGroup;
|
if (blockGroup != null) return blockGroup;
|
||||||
if (!GameState.IsBuildMode()) return null; // Breaks in simulation
|
|
||||||
var bgec = BlockEngine.GetBlockInfo<BlockGroupEntityComponent>(this);
|
var bgec = BlockEngine.GetBlockInfo<BlockGroupEntityComponent>(this);
|
||||||
return blockGroup = bgec.currentBlockGroup == -1
|
return blockGroup = bgec.currentBlockGroup == -1 ? null : new BlockGroup(bgec.currentBlockGroup, this);
|
||||||
? null
|
|
||||||
: GetInstance(new EGID((uint)bgec.currentBlockGroup, BlockGroupExclusiveGroups.BlockGroupEntityGroup),
|
|
||||||
egid => new BlockGroup((int)egid.entityID, this));
|
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
@ -399,23 +392,6 @@ namespace TechbloxModdingAPI
|
||||||
set => BlockEngine.GetBlockInfo<BlockStaticComponent>(this).isStatic = value;
|
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>
|
/// <summary>
|
||||||
/// Whether the block exists. The other properties will return a default value if the block doesn't exist.
|
/// 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.
|
/// If the block was just placed, then this will also return false but the properties will work correctly.
|
||||||
|
@ -441,10 +417,9 @@ namespace TechbloxModdingAPI
|
||||||
public SimBody GetSimBody()
|
public SimBody GetSimBody()
|
||||||
{
|
{
|
||||||
var st = BlockEngine.GetBlockInfo<GridConnectionsEntityStruct>(this);
|
var st = BlockEngine.GetBlockInfo<GridConnectionsEntityStruct>(this);
|
||||||
/*return st.machineRigidBodyId != uint.MaxValue
|
return st.machineRigidBodyId != uint.MaxValue
|
||||||
? new SimBody(st.machineRigidBodyId, st.clusterId) - TODO:
|
? new SimBody(st.machineRigidBodyId, st.clusterId)
|
||||||
: null;*/
|
: null;
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
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 };
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -274,110 +274,11 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
/// The grid block used by the world editor, named Small Grid like the other one
|
/// The grid block used by the world editor, named Small Grid like the other one
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SmallGridInWorldEditor,
|
SmallGridInWorldEditor,
|
||||||
CityDoubleCrossing,
|
SegoeUITextblock = 376,
|
||||||
CityDoubleCrossroads,
|
|
||||||
CitySmallDoubleJunction,
|
|
||||||
CityDoubleJunction,
|
|
||||||
CityDoubleToSingleJunction,
|
|
||||||
CitySmallDoubleRoad,
|
|
||||||
CityDoubleRoad,
|
|
||||||
CitySmallDoubleTurn,
|
|
||||||
CityLargeDoubleTurn,
|
|
||||||
CitySmallSingleTurn,
|
|
||||||
CityLargeSingleTurn,
|
|
||||||
CitySingleJunction,
|
|
||||||
CitySingleRoad,
|
|
||||||
SegoeUITextblock,
|
|
||||||
GravtracTextblock,
|
GravtracTextblock,
|
||||||
HauserTextblock,
|
HauserTextblock,
|
||||||
TechnopollasTextblock,
|
TechnopollasTextblock,
|
||||||
CityDoubleHillRoad,
|
BitBlock = 385,
|
||||||
DiagonalTrackTile,
|
Timer
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -31,16 +31,5 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
SteelBodyworkPaintedChipped,
|
SteelBodyworkPaintedChipped,
|
||||||
WoodPainted,
|
WoodPainted,
|
||||||
WoodRoughGrungy,
|
WoodRoughGrungy,
|
||||||
Boundary,
|
|
||||||
Emissive,
|
|
||||||
AircraftPanelingRivetedPainted,
|
|
||||||
AircraftPanelingRivetedMetallic,
|
|
||||||
SteelBodyworkPearlescent,
|
|
||||||
SteelBodyworkRadWrap,
|
|
||||||
SteelBodyworkGlitter,
|
|
||||||
BouncyRubber,
|
|
||||||
BouncyRubberTieDye,
|
|
||||||
BrickPainted,
|
|
||||||
FuturisticPanelingRivetedPainted,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,8 +5,11 @@ using System.Reflection;
|
||||||
|
|
||||||
using DataLoader;
|
using DataLoader;
|
||||||
using Svelto.Tasks;
|
using Svelto.Tasks;
|
||||||
|
using Svelto.Tasks.Enumerators;
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
using TechbloxModdingAPI.App;
|
||||||
using TechbloxModdingAPI.Tests;
|
using TechbloxModdingAPI.Tests;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
|
|
||||||
|
@ -79,50 +82,42 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
yield break;
|
yield break;
|
||||||
for (var index = 0; index < blocks.Length; index++)
|
for (var index = 0; index < blocks.Length; index++)
|
||||||
{
|
{
|
||||||
|
if (index % 50 == 0) yield return Yield.It; //The material or flipped status can only be changed 130 times per submission
|
||||||
var block = blocks[index];
|
var block = blocks[index];
|
||||||
if (!block.Exists) continue;
|
if (!block.Exists) continue;
|
||||||
foreach (var property in block.GetType().GetProperties())
|
foreach (var property in block.GetType().GetProperties())
|
||||||
{
|
{
|
||||||
|
if (property.Name == "Material" || property.Name == "Flipped") continue; // TODO: Crashes in game
|
||||||
|
if (property.Name == "Material" || property.Name == "Flipped")
|
||||||
|
{
|
||||||
|
Console.WriteLine("Block type: "+block.Type);
|
||||||
|
Console.WriteLine("Will set " + property.Name);
|
||||||
|
yield return new WaitForSecondsEnumerator(1).Continue();
|
||||||
|
}
|
||||||
//Includes specialised block properties
|
//Includes specialised block properties
|
||||||
if (property.SetMethod == null) continue;
|
if (property.SetMethod == null) continue;
|
||||||
|
var testValues = new (Type, object, Predicate<object>)[]
|
||||||
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)
|
//(type, default value, predicate or null for equality)
|
||||||
(typeof(long), 3, null),
|
(typeof(long), 3, null),
|
||||||
(typeof(int), 4, null),
|
(typeof(int), 4, null),
|
||||||
(typeof(double), 5.2f, t => Math.Abs((double) t.Value - (double) t.Default) < float.Epsilon),
|
(typeof(double), 5.2f, obj => Math.Abs((double) obj - 5.2f) < float.Epsilon),
|
||||||
(typeof(float), 5.2f, t => Math.Abs((float) t.Value - (float) t.Default) < float.Epsilon),
|
(typeof(float), 5.2f, obj => Math.Abs((float) obj - 5.2f) < float.Epsilon),
|
||||||
(typeof(bool), true, t => (bool) t.Value),
|
(typeof(bool), true, obj => (bool) obj),
|
||||||
(typeof(string), "Test", t => (string) t.Value == "Test"), //String equality check
|
(typeof(string), "Test", obj => (string) obj == "Test"), //String equality check
|
||||||
(typeof(float3), (float3) 20, t => math.all(Float3Compare((float3)t.Value, (float3)t.Default))),
|
(typeof(float3), (float3) 2, obj => math.all((float3) obj - 2 < (float3) float.Epsilon)),
|
||||||
(typeof(BlockColor), new BlockColor(BlockColors.Aqua, 2), null),
|
(typeof(BlockColor), new BlockColor(BlockColors.Aqua, 2), null),
|
||||||
(typeof(float4), (float4) 5, t => math.all(Float4Compare((float4)t.Value, (float4)t.Default)))
|
(typeof(float4), (float4) 5, obj => math.all((float4) obj - 5 < (float4) float.Epsilon))
|
||||||
};
|
};
|
||||||
var propType = property.PropertyType;
|
var propType = property.PropertyType;
|
||||||
if (!propType.IsValueType) continue;
|
if (!propType.IsValueType) continue;
|
||||||
(object valueToUse, Predicate<(object Value, object Default)> predicateToUse) = (null, null);
|
(object valueToUse, Predicate<object> predicateToUse) = (null, null);
|
||||||
foreach (var (type, value, predicate) in testValues)
|
foreach (var (type, value, predicate) in testValues)
|
||||||
{
|
{
|
||||||
if (type.IsAssignableFrom(propType))
|
if (type.IsAssignableFrom(propType))
|
||||||
{
|
{
|
||||||
valueToUse = value;
|
valueToUse = value;
|
||||||
predicateToUse = predicate ?? (t => Equals(t.Value, t.Default));
|
predicateToUse = predicate ?? (obj => Equals(obj, value));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,7 +126,7 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
{
|
{
|
||||||
var values = propType.GetEnumValues();
|
var values = propType.GetEnumValues();
|
||||||
valueToUse = values.GetValue(values.Length / 2);
|
valueToUse = values.GetValue(values.Length / 2);
|
||||||
predicateToUse = t => Equals(t.Value, t.Default);
|
predicateToUse = val => Equals(val, valueToUse);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valueToUse == null)
|
if (valueToUse == null)
|
||||||
|
@ -159,7 +154,7 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var attr = property.GetCustomAttribute<TestValueAttribute>();
|
var attr = property.GetCustomAttribute<TestValueAttribute>();
|
||||||
if (!predicateToUse((got, valueToUse)) && (attr == null || !Equals(attr.PossibleValue, got)))
|
if (!predicateToUse(got) && (attr == null || !Equals(attr.PossibleValue, got)))
|
||||||
{
|
{
|
||||||
Assert.Fail($"Property {block.GetType().Name}.{property.Name} value {got} does not equal {valueToUse} for block {block}.");
|
Assert.Fail($"Property {block.GetType().Name}.{property.Name} value {got} does not equal {valueToUse} for block {block}.");
|
||||||
yield break;
|
yield break;
|
||||||
|
|
|
@ -22,8 +22,8 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
base(new EGID(id, CommonExclusiveGroups.ENGINE_BLOCK_BUILD_GROUP))
|
base(new EGID(id, CommonExclusiveGroups.ENGINE_BLOCK_BUILD_GROUP))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
/*/// <summary> - TODO: Internal struct access
|
/// <summary>
|
||||||
/// Gets or sets the Engine's On property. May not be saved.
|
/// Gets or sets the Engine's On property. May not be saved.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool On
|
public bool On
|
||||||
|
@ -34,6 +34,7 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
Techblox.BlockColours.BlockColoursCompositionRoot
|
||||||
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).engineOn = value;
|
BlockEngine.GetBlockInfo<Techblox.EngineBlock.EngineBlockComponent>(this).engineOn = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,8 +48,8 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
pickedBlock.pickedBlockEntityID = sourceID;
|
pickedBlock.pickedBlockEntityID = sourceID;
|
||||||
pickedBlock.placedBlockEntityID = targetID;
|
pickedBlock.placedBlockEntityID = targetID;
|
||||||
pickedBlock.placedBlockTweaksMustCopy = true;
|
pickedBlock.placedBlockTweaksMustCopy = true;
|
||||||
if (entitiesDB.Exists<BlockTagEntityStruct>(pickedBlock.pickedBlockEntityID)
|
if (entitiesDB.Exists<DBEntityStruct>(pickedBlock.pickedBlockEntityID)
|
||||||
&& entitiesDB.Exists<BlockTagEntityStruct>(pickedBlock.placedBlockEntityID))
|
&& entitiesDB.Exists<DBEntityStruct>(pickedBlock.placedBlockEntityID))
|
||||||
{
|
{
|
||||||
copyFromBlock.Invoke(Patch.copyEngine, new object[] {pickedBlock.ID, pickedBlock});
|
copyFromBlock.Invoke(Patch.copyEngine, new object[] {pickedBlock.ID, pickedBlock});
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
|
|
||||||
using Gamecraft.ColourPalette;
|
using Gamecraft.ColourPalette;
|
||||||
|
using Gamecraft.TimeRunning;
|
||||||
using Gamecraft.Wires;
|
using Gamecraft.Wires;
|
||||||
using RobocraftX.Blocks;
|
using RobocraftX.Blocks;
|
||||||
using RobocraftX.Common;
|
using RobocraftX.Common;
|
||||||
|
@ -12,17 +13,12 @@ using RobocraftX.Rendering;
|
||||||
using RobocraftX.Rendering.GPUI;
|
using RobocraftX.Rendering.GPUI;
|
||||||
using Svelto.DataStructures;
|
using Svelto.DataStructures;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.EntityStructs;
|
|
||||||
using Svelto.ECS.Experimental;
|
|
||||||
using Svelto.ECS.Hybrid;
|
using Svelto.ECS.Hybrid;
|
||||||
using Techblox.BuildingDrone;
|
using Techblox.BuildingDrone;
|
||||||
using Techblox.ObjectIDBlockServer;
|
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
|
|
||||||
using TechbloxModdingAPI.Engines;
|
using TechbloxModdingAPI.Engines;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
using TechbloxModdingAPI.Utility.ECS;
|
|
||||||
using PrefabsID = RobocraftX.Common.PrefabsID;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Blocks.Engines
|
namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
{
|
{
|
||||||
|
@ -47,21 +43,22 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
|
||||||
public Block[] GetConnectedBlocks(EGID blockID)
|
public Block[] GetConnectedBlocks(EGID blockID)
|
||||||
{
|
{
|
||||||
if (!BlockExists(blockID)) return Array.Empty<Block>();
|
if (!BlockExists(blockID)) return new Block[0];
|
||||||
Stack<EGID> cubeStack = new Stack<EGID>();
|
Stack<EGID> cubeStack = new Stack<EGID>();
|
||||||
FasterList<EGID> cubes = new FasterList<EGID>(10);
|
FasterList<EGID> cubes = new FasterList<EGID>(10);
|
||||||
var coll = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
|
var coll = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
|
||||||
foreach (var ((ecoll, count), _) in coll)
|
foreach (var (ecoll, _) in coll)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < count; i++)
|
var ecollB = ecoll.ToBuffer();
|
||||||
|
for(int i = 0; i < ecoll.count; i++)
|
||||||
{
|
{
|
||||||
ecoll[i].areConnectionsAssigned = false;
|
ref var conn = ref ecollB.buffer[i];
|
||||||
|
conn.isProcessed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: GetConnectedCubesUtility
|
ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubeStack, cubes,
|
||||||
/*ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubeStack, cubes,
|
(in GridConnectionsEntityStruct g) => { return false; });
|
||||||
(in GridConnectionsEntityStruct _) => false);*/
|
|
||||||
|
|
||||||
var ret = new Block[cubes.count];
|
var ret = new Block[cubes.count];
|
||||||
for (int i = 0; i < cubes.count; i++)
|
for (int i = 0; i < cubes.count; i++)
|
||||||
|
@ -72,7 +69,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
public float4 ConvertBlockColor(byte index) => index == byte.MaxValue
|
public float4 ConvertBlockColor(byte index) => index == byte.MaxValue
|
||||||
? new float4(-1f, -1f, -1f, -1f)
|
? new float4(-1f, -1f, -1f, -1f)
|
||||||
: entitiesDB.QueryEntity<PaletteEntryEntityStruct>(index,
|
: entitiesDB.QueryEntity<PaletteEntryEntityStruct>(index,
|
||||||
ColourPaletteExclusiveGroups.COLOUR_PALETTE_GROUP).Colour;
|
CommonExclusiveGroups.COLOUR_PALETTE_GROUP).Colour;
|
||||||
|
|
||||||
public OptionalRef<T> GetBlockInfoOptional<T>(Block block) where T : unmanaged, IEntityComponent
|
public OptionalRef<T> GetBlockInfoOptional<T>(Block block) where T : unmanaged, IEntityComponent
|
||||||
{
|
{
|
||||||
|
@ -81,10 +78,6 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
|
||||||
public ref T GetBlockInfo<T>(Block block) where T : unmanaged, IEntityComponent
|
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);
|
return ref entitiesDB.QueryEntityOrDefault<T>(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,35 +91,10 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
return ref entitiesDB.QueryEntityOrDefault<T>(block);
|
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)
|
public void UpdateDisplayedBlock(EGID id)
|
||||||
{
|
{
|
||||||
if (!BlockExists(id)) return;
|
if (!BlockExists(id)) return;
|
||||||
var pos = entitiesDB.QueryEntity<PositionEntityStruct>(id);
|
RenderingPatch.UpdateBlocks();
|
||||||
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)
|
internal void UpdatePrefab(Block block, byte material, bool flipped)
|
||||||
|
@ -137,58 +105,57 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
: uint.MaxValue;
|
: uint.MaxValue;
|
||||||
if (prefabAssetID == uint.MaxValue)
|
if (prefabAssetID == uint.MaxValue)
|
||||||
{
|
{
|
||||||
if (entitiesDB.QueryEntityOptional<BlockTagEntityStruct>(block)) //The block exists
|
if (entitiesDB.QueryEntityOptional<DBEntityStruct>(block)) //The block exists
|
||||||
throw new BlockException("Prefab asset ID not found for block " + block); //Set by the game
|
throw new BlockException("Prefab asset ID not found for block " + block); //Set by the game
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint prefabId =
|
uint prefabId =
|
||||||
PrefabsID.GetOrAddPrefabID((ushort) prefabAssetID, material, 1, flipped);
|
PrefabsID.GetOrCreatePrefabID((ushort) prefabAssetID, material, 1, flipped);
|
||||||
entitiesDB.QueryEntityOrDefault<GFXPrefabEntityStructGPUI>(block).prefabID = prefabId;
|
entitiesDB.QueryEntityOrDefault<GFXPrefabEntityStructGPUI>(block).prefabID = prefabId;
|
||||||
if (block.Exists)
|
if (block.Exists)
|
||||||
{
|
{
|
||||||
entitiesDB.PublishEntityChangeDelayed<CubeMaterialStruct>(block.Id);
|
entitiesDB.PublishEntityChange<CubeMaterialStruct>(block.Id);
|
||||||
entitiesDB.PublishEntityChangeDelayed<GFXPrefabEntityStructGPUI>(block.Id);
|
entitiesDB.PublishEntityChange<GFXPrefabEntityStructGPUI>(block.Id);
|
||||||
|
|
||||||
ref BuildingActionComponent local =
|
ref BuildingActionComponent local =
|
||||||
ref entitiesDB.QueryEntity<BuildingActionComponent>(BuildingDroneUtility
|
ref entitiesDB.QueryEntity<BuildingActionComponent>(BuildingDroneUtility
|
||||||
.GetLocalBuildingDrone(entitiesDB).ToEGID(entitiesDB));
|
.GetLocalBuildingDrone(entitiesDB).ToEGID(entitiesDB));
|
||||||
local.buildAction = BuildAction.ChangeMaterial;
|
local.buildAction = BuildAction.ChangeMaterial;
|
||||||
local.targetPosition = block.Position;
|
local.targetPosition = block.Position;
|
||||||
this.entitiesDB.PublishEntityChangeDelayed<BuildingActionComponent>(local.ID);
|
this.entitiesDB.PublishEntityChange<BuildingActionComponent>(local.ID);
|
||||||
}
|
}
|
||||||
//Phyiscs prefab: prefabAssetID, set on block creation from the CubeListData
|
//Phyiscs prefab: prefabAssetID, set on block creation from the CubeListData
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateBlockColor(EGID id)
|
|
||||||
{
|
|
||||||
entitiesDB.PublishEntityChangeDelayed<ColourParameterEntityStruct>(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool BlockExists(EGID blockID)
|
public bool BlockExists(EGID blockID)
|
||||||
{
|
{
|
||||||
return entitiesDB.Exists<BlockTagEntityStruct>(blockID);
|
return entitiesDB.Exists<DBEntityStruct>(blockID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SimBody[] GetSimBodiesFromID(byte id)
|
public SimBody[] GetSimBodiesFromID(byte id)
|
||||||
{
|
{
|
||||||
var ret = new FasterList<SimBody>(4);
|
var ret = new FasterList<SimBody>(4);
|
||||||
var oids = entitiesDB.QueryEntitiesOptional<ObjectIdEntityStruct>(ObjectIDBlockExclusiveGroups.OBJECT_ID_BLOCK_GROUP);
|
var oide = entitiesDB.QueryEntities<ObjectIdEntityStruct>();
|
||||||
EGIDMapper<GridConnectionsEntityStruct>? connections = null;
|
EGIDMapper<GridConnectionsEntityStruct>? connections = null;
|
||||||
foreach (var oid in oids)
|
foreach (var ((oids, count), _) in oide)
|
||||||
{
|
{
|
||||||
if (oid.Get().objectId != id) continue;
|
for (int i = 0; i < count; i++)
|
||||||
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)
|
ref ObjectIdEntityStruct oid = ref oids[i];
|
||||||
goto DUPLICATE; //Multiple Object Identifiers on one rigid body
|
if (oid.objectId != id) continue;
|
||||||
}
|
if (!connections.HasValue) //Would need reflection to get the group from the build group otherwise
|
||||||
|
connections = entitiesDB.QueryMappedEntities<GridConnectionsEntityStruct>(oid.ID.groupID);
|
||||||
|
var rid = connections.Value.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));
|
ret.Add(new SimBody(rid));
|
||||||
DUPLICATE: ;*/
|
DUPLICATE: ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret.ToArray();
|
return ret.ToArray();
|
||||||
|
@ -196,14 +163,14 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
|
||||||
public SimBody[] GetConnectedSimBodies(uint id)
|
public SimBody[] GetConnectedSimBodies(uint id)
|
||||||
{
|
{
|
||||||
var (joints, count) = entitiesDB.QueryEntities<JointEntityStruct>(MachineSimulationGroups.JOINTS_GROUP);
|
var joints = entitiesDB.QueryEntities<JointEntityStruct>(MachineSimulationGroups.JOINTS_GROUP).ToBuffer();
|
||||||
var list = new FasterList<SimBody>(4);
|
var list = new FasterList<SimBody>(4);
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < joints.count; i++)
|
||||||
{
|
{
|
||||||
ref var joint = ref joints[i];
|
ref var joint = ref joints.buffer[i];
|
||||||
if (joint.isBroken) continue;
|
if (joint.isBroken) continue;
|
||||||
/*if (joint.connectedEntityA == id) list.Add(new SimBody(joint.connectedEntityB)); - TODO:
|
if (joint.connectedEntityA == id) list.Add(new SimBody(joint.connectedEntityB));
|
||||||
else if (joint.connectedEntityB == id) list.Add(new SimBody(joint.connectedEntityA));*/
|
else if (joint.connectedEntityB == id) list.Add(new SimBody(joint.connectedEntityA));
|
||||||
}
|
}
|
||||||
|
|
||||||
return list.ToArray();
|
return list.ToArray();
|
||||||
|
@ -213,13 +180,14 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
{
|
{
|
||||||
var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
|
var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
|
||||||
var bodies = new HashSet<uint>();
|
var bodies = new HashSet<uint>();
|
||||||
foreach (var ((coll, count), _) in groups)
|
foreach (var (coll, _) in groups)
|
||||||
{
|
{
|
||||||
for (var index = 0; index < count; index++)
|
var array = coll.ToBuffer().buffer;
|
||||||
|
for (var index = 0; index < array.capacity; index++)
|
||||||
{
|
{
|
||||||
var conn = coll[index];
|
var conn = array[index];
|
||||||
/*if (conn.clusterId == cid) - TODO
|
if (conn.clusterId == cid)
|
||||||
bodies.Add(conn.machineRigidBodyId);*/
|
bodies.Add(conn.machineRigidBodyId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,10 +196,10 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
|
||||||
public EGID? FindBlockEGID(uint id)
|
public EGID? FindBlockEGID(uint id)
|
||||||
{
|
{
|
||||||
var groups = entitiesDB.FindGroups<BlockTagEntityStruct>();
|
var groups = entitiesDB.FindGroups<DBEntityStruct>();
|
||||||
foreach (ExclusiveGroupStruct group in groups)
|
foreach (ExclusiveGroupStruct group in groups)
|
||||||
{
|
{
|
||||||
if (entitiesDB.Exists<BlockTagEntityStruct>(id, group))
|
if (entitiesDB.Exists<DBEntityStruct>(id, group))
|
||||||
return new EGID(id, group);
|
return new EGID(id, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,14 +209,15 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
public Cluster GetCluster(uint sbid)
|
public Cluster GetCluster(uint sbid)
|
||||||
{
|
{
|
||||||
var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
|
var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
|
||||||
foreach (var ((coll, count), _) in groups)
|
foreach (var (coll, _) in groups)
|
||||||
{
|
{
|
||||||
for (var index = 0; index < count; index++)
|
var array = coll.ToBuffer().buffer;
|
||||||
|
for (var index = 0; index < array.capacity; index++)
|
||||||
{
|
{
|
||||||
var conn = coll[index];
|
var conn = array[index];
|
||||||
//Static blocks don't have a cluster ID but the cluster destruction manager should have one
|
//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:
|
if (conn.machineRigidBodyId == sbid && conn.clusterId != uint.MaxValue)
|
||||||
return new Cluster(conn.clusterId);*/
|
return new Cluster(conn.clusterId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,36 +226,49 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
|
||||||
public Block[] GetBodyBlocks(uint sbid)
|
public Block[] GetBodyBlocks(uint sbid)
|
||||||
{
|
{
|
||||||
var groups = entitiesDB.FindGroups<GridConnectionsEntityStruct>();
|
var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
|
||||||
groups = new QueryGroups(groups).Except(CommonExclusiveGroups.DISABLED_JOINTS_IN_SIM_GROUP).Evaluate().result;
|
|
||||||
var set = new HashSet<Block>();
|
var set = new HashSet<Block>();
|
||||||
foreach (var ((coll, tags, count), _) in entitiesDB.QueryEntities<GridConnectionsEntityStruct, BlockTagEntityStruct>(groups))
|
foreach (var (coll, _) in groups)
|
||||||
{
|
{
|
||||||
for (var index = 0; index < count; index++)
|
var array = coll.ToBuffer().buffer;
|
||||||
|
for (var index = 0; index < array.capacity; index++)
|
||||||
{
|
{
|
||||||
var conn = coll[index];
|
var conn = array[index];
|
||||||
/*if (conn.machineRigidBodyId == sbid) - TODO
|
if (conn.machineRigidBodyId == sbid)
|
||||||
set.Add(Block.New(tags[index].ID));*/
|
set.Add(Block.New(conn.ID));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return set.ToArray();
|
return set.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectID[] GetObjectIDsFromID(byte id)
|
#if DEBUG
|
||||||
|
public EntitiesDB GetEntitiesDB()
|
||||||
{
|
{
|
||||||
if (!entitiesDB.HasAny<ObjectIDTweakableComponent>(ObjectIDBlockExclusiveGroups.OBJECT_ID_BLOCK_GROUP))
|
return entitiesDB;
|
||||||
return Array.Empty<ObjectID>();
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
var ret = new FasterList<ObjectID>(4);
|
[HarmonyPatch]
|
||||||
var oids = entitiesDB.QueryEntitiesOptional<ObjectIDTweakableComponent>(ObjectIDBlockExclusiveGroups.OBJECT_ID_BLOCK_GROUP);
|
public static class RenderingPatch
|
||||||
foreach (var oid in oids)
|
{
|
||||||
|
private static ComputeRenderingEntitiesMatricesEngine Engine;
|
||||||
|
|
||||||
|
public static void Postfix(ComputeRenderingEntitiesMatricesEngine __instance)
|
||||||
{
|
{
|
||||||
if (oid.Get().objectIDToTrigger == id)
|
Engine = __instance;
|
||||||
ret.Add(new ObjectID(oid.EGID));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret.ToArray();
|
public static MethodBase TargetMethod()
|
||||||
|
{
|
||||||
|
return typeof(ComputeRenderingEntitiesMatricesEngine).GetConstructors()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UpdateBlocks()
|
||||||
|
{
|
||||||
|
var data = new RenderingDataStruct();
|
||||||
|
Engine.Add(ref data, new EGID(0, CommonExclusiveGroups.BUTTON_BLOCK_GROUP));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,13 +26,18 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
public string Name { get; } = "TechbloxModdingAPIBlockEventsEngine";
|
public string Name { get; } = "TechbloxModdingAPIBlockEventsEngine";
|
||||||
public bool isRemovable { get; } = false;
|
public bool isRemovable { get; } = false;
|
||||||
|
|
||||||
|
private bool shouldAddRemove;
|
||||||
public void Add(ref BlockTagEntityStruct entityComponent, EGID egid)
|
public void Add(ref BlockTagEntityStruct entityComponent, EGID egid)
|
||||||
{
|
{
|
||||||
|
if (!(shouldAddRemove = !shouldAddRemove))
|
||||||
|
return;
|
||||||
Placed.Invoke(this, new BlockPlacedRemovedEventArgs {ID = egid});
|
Placed.Invoke(this, new BlockPlacedRemovedEventArgs {ID = egid});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(ref BlockTagEntityStruct entityComponent, EGID egid)
|
public void Remove(ref BlockTagEntityStruct entityComponent, EGID egid)
|
||||||
{
|
{
|
||||||
|
if (!(shouldAddRemove = !shouldAddRemove))
|
||||||
|
return;
|
||||||
Removed.Invoke(this, new BlockPlacedRemovedEventArgs {ID = egid});
|
Removed.Invoke(this, new BlockPlacedRemovedEventArgs {ID = egid});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,9 @@ using Svelto.ECS.DataStructures;
|
||||||
using Svelto.ECS.EntityStructs;
|
using Svelto.ECS.EntityStructs;
|
||||||
using Svelto.ECS.Native;
|
using Svelto.ECS.Native;
|
||||||
using Svelto.ECS.Serialization;
|
using Svelto.ECS.Serialization;
|
||||||
using Techblox.Blocks.Connections;
|
using Techblox.Blocks;
|
||||||
using TechbloxModdingAPI.Engines;
|
using TechbloxModdingAPI.Engines;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
using TechbloxModdingAPI.Utility.ECS;
|
|
||||||
using Unity.Collections;
|
using Unity.Collections;
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
@ -49,8 +48,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
private static readonly MethodInfo SerializeGhostBlueprint =
|
private static readonly MethodInfo SerializeGhostBlueprint =
|
||||||
AccessTools.Method(SerializeGhostBlueprintType, "SerializeClipboardGhostEntities");
|
AccessTools.Method(SerializeGhostBlueprintType, "SerializeClipboardGhostEntities");
|
||||||
|
|
||||||
private static NativeEntityRemove nativeBlockRemove;
|
private static NativeEntityRemove nativeRemove;
|
||||||
private static NativeEntityRemove nativeConnectionRemove;
|
|
||||||
private static MachineGraphConnectionEntityFactory connectionFactory;
|
private static MachineGraphConnectionEntityFactory connectionFactory;
|
||||||
private static IEntityFunctions entityFunctions;
|
private static IEntityFunctions entityFunctions;
|
||||||
private static ClipboardSerializationDataResourceManager clipboardManager;
|
private static ClipboardSerializationDataResourceManager clipboardManager;
|
||||||
|
@ -90,8 +88,8 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
|
||||||
public void RemoveBlockGroup(int id)
|
public void RemoveBlockGroup(int id)
|
||||||
{
|
{
|
||||||
BlockGroupUtility.RemoveAllBlocksInBlockGroup(id, entitiesDB, removedConnections, nativeBlockRemove,
|
BlockGroupUtility.RemoveAllBlocksInBlockGroup(id, entitiesDB, removedConnections, nativeRemove,
|
||||||
nativeConnectionRemove, connectionFactory, default).Complete();
|
connectionFactory, default).Complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CreateBlockGroup(float3 position, quaternion rotation)
|
public int CreateBlockGroup(float3 position, quaternion rotation)
|
||||||
|
@ -279,7 +277,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
FullGameFields._managers.blockLabelResourceManager);
|
FullGameFields._managers.blockLabelResourceManager);
|
||||||
entityInitializer.Init(dbStruct);
|
entityInitializer.Init(dbStruct);
|
||||||
entityInitializer.Init(new GFXPrefabEntityStructGPUI(
|
entityInitializer.Init(new GFXPrefabEntityStructGPUI(
|
||||||
PrefabsID.GetOrAddPrefabID((ushort)entityInitializer.Get<PrefabAssetIDComponent>().prefabAssetID,
|
PrefabsID.GetOrCreatePrefabID((ushort)entityInitializer.Get<PrefabAssetIDComponent>().prefabAssetID,
|
||||||
entitiesDB.QueryEntity<CubeMaterialStruct>(sourceId).materialId, 7,
|
entitiesDB.QueryEntity<CubeMaterialStruct>(sourceId).materialId, 7,
|
||||||
FlippedBlockUtils.IsFlipped(in scalingEntityStruct.scale)), true));
|
FlippedBlockUtils.IsFlipped(in scalingEntityStruct.scale)), true));
|
||||||
entityInitializer.Init(entitiesDB.QueryEntity<CubeMaterialStruct>(sourceId));
|
entityInitializer.Init(entitiesDB.QueryEntity<CubeMaterialStruct>(sourceId));
|
||||||
|
@ -341,8 +339,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
public static void Prefix(IEntityFunctions entityFunctions,
|
public static void Prefix(IEntityFunctions entityFunctions,
|
||||||
MachineGraphConnectionEntityFactory machineGraphConnectionEntityFactory)
|
MachineGraphConnectionEntityFactory machineGraphConnectionEntityFactory)
|
||||||
{
|
{
|
||||||
nativeBlockRemove = entityFunctions.ToNativeRemove<BlockEntityDescriptor>("TBAPI" + nameof(BlueprintEngine));
|
nativeRemove = entityFunctions.ToNativeRemove<BlockEntityDescriptor>("GCAPI" + nameof(BlueprintEngine));
|
||||||
nativeConnectionRemove = entityFunctions.ToNativeRemove<MachineConnectionEntityDescriptor>("TBAPI" + nameof(BlueprintEngine));
|
|
||||||
connectionFactory = machineGraphConnectionEntityFactory;
|
connectionFactory = machineGraphConnectionEntityFactory;
|
||||||
BlueprintEngine.entityFunctions = entityFunctions;
|
BlueprintEngine.entityFunctions = entityFunctions;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ using Unity.Transforms;
|
||||||
|
|
||||||
using TechbloxModdingAPI.Engines;
|
using TechbloxModdingAPI.Engines;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
using TechbloxModdingAPI.Utility.ECS;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Blocks.Engines
|
namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
{
|
{
|
||||||
|
@ -41,7 +40,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntityOrDefault<PositionEntityStruct>(block);
|
ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntityOrDefault<PositionEntityStruct>(block);
|
||||||
ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntityOrDefault<GridRotationStruct>(block);
|
ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntityOrDefault<GridRotationStruct>(block);
|
||||||
ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntityOrDefault<LocalTransformEntityStruct>(block);
|
ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntityOrDefault<LocalTransformEntityStruct>(block);
|
||||||
var phyStruct = this.entitiesDB.QueryEntityOptional<DOTSPhysicsEntityStruct>(block);
|
ref DOTSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntityOrDefault<DOTSPhysicsEntityStruct>(block);
|
||||||
// main (persistent) position
|
// main (persistent) position
|
||||||
posStruct.position = vector;
|
posStruct.position = vector;
|
||||||
// placement grid position
|
// placement grid position
|
||||||
|
@ -49,15 +48,15 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
// rendered position
|
// rendered position
|
||||||
transStruct.position = vector;
|
transStruct.position = vector;
|
||||||
// collision position
|
// collision position
|
||||||
if (phyStruct)
|
if (phyStruct.ID != default)
|
||||||
{ //It exists
|
{ //It exists
|
||||||
FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.Get().dotsEntity, new Translation
|
FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.dotsEntity, new Translation
|
||||||
{
|
{
|
||||||
Value = posStruct.position
|
Value = posStruct.position
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
entitiesDB.QueryEntityOrDefault<GridConnectionsEntityStruct>(block).areConnectionsAssigned = false;
|
entitiesDB.QueryEntityOrDefault<GridConnectionsEntityStruct>(block).isProcessed = false;
|
||||||
return posStruct.position;
|
return posStruct.position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ using Unity.Mathematics;
|
||||||
|
|
||||||
using TechbloxModdingAPI.Engines;
|
using TechbloxModdingAPI.Engines;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
using TechbloxModdingAPI.Utility.ECS;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Blocks.Engines
|
namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
{
|
{
|
||||||
|
@ -55,11 +54,12 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
//RobocraftX.CR.MachineEditing.PlaceSingleBlockEngine
|
//RobocraftX.CR.MachineEditing.PlaceSingleBlockEngine
|
||||||
DBEntityStruct dbEntity = new DBEntityStruct {DBID = block};
|
DBEntityStruct dbEntity = new DBEntityStruct {DBID = block};
|
||||||
|
|
||||||
|
//TODO: Test
|
||||||
EntityInitializer structInitializer = _blockEntityFactory.Build(CommonExclusiveGroups.blockIDGeneratorClient.Next(), block); //The ghost block index is only used for triggers
|
EntityInitializer structInitializer = _blockEntityFactory.Build(CommonExclusiveGroups.blockIDGeneratorClient.Next(), block); //The ghost block index is only used for triggers
|
||||||
uint prefabAssetID = structInitializer.Has<PrefabAssetIDComponent>()
|
uint prefabAssetID = structInitializer.Has<PrefabAssetIDComponent>()
|
||||||
? structInitializer.Get<PrefabAssetIDComponent>().prefabAssetID
|
? structInitializer.Get<PrefabAssetIDComponent>().prefabAssetID
|
||||||
: throw new BlockException("Prefab asset ID not found!"); //Set by the game
|
: throw new BlockException("Prefab asset ID not found!"); //Set by the game
|
||||||
uint prefabId = PrefabsID.GetOrAddPrefabID((ushort) prefabAssetID, (byte) BlockMaterial.SteelBodywork, 1, false);
|
uint prefabId = PrefabsID.GetOrCreatePrefabID((ushort) prefabAssetID, (byte) BlockMaterial.SteelBodywork, 1, false);
|
||||||
structInitializer.Init(new GFXPrefabEntityStructGPUI(prefabId));
|
structInitializer.Init(new GFXPrefabEntityStructGPUI(prefabId));
|
||||||
structInitializer.Init(dbEntity);
|
structInitializer.Init(dbEntity);
|
||||||
structInitializer.Init(new PositionEntityStruct {position = position});
|
structInitializer.Init(new PositionEntityStruct {position = position});
|
||||||
|
|
|
@ -1,61 +1,47 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
using Gamecraft.Blocks.BlockGroups;
|
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using RobocraftX.Blocks;
|
using RobocraftX.Blocks;
|
||||||
using RobocraftX.Common;
|
using RobocraftX.Common;
|
||||||
using RobocraftX.GroupTags;
|
using Svelto.Common;
|
||||||
using RobocraftX.StateSync;
|
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.Native;
|
using Svelto.ECS.Native;
|
||||||
using Techblox.Blocks.Connections;
|
|
||||||
using Unity.Collections;
|
|
||||||
using Unity.Jobs;
|
|
||||||
using Allocator = Unity.Collections.Allocator;
|
|
||||||
|
|
||||||
using TechbloxModdingAPI.Engines;
|
using TechbloxModdingAPI.Engines;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Blocks.Engines
|
namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
{
|
{
|
||||||
public class RemovalEngine : IApiEngine, IDeterministicTimeStopped
|
public class RemovalEngine : IApiEngine
|
||||||
{
|
{
|
||||||
private static IEntityFunctions _entityFunctions;
|
private static IEntityFunctions _entityFunctions;
|
||||||
private static MachineGraphConnectionEntityFactory _connectionFactory;
|
private static MachineGraphConnectionEntityFactory _connectionFactory;
|
||||||
private NativeHashSet<ulong> removedConnections;
|
|
||||||
|
|
||||||
public bool RemoveBlock(EGID target)
|
public bool RemoveBlock(EGID target)
|
||||||
{
|
{
|
||||||
if (!entitiesDB.Exists<MachineGraphConnectionsEntityStruct>(target))
|
if (!entitiesDB.Exists<MachineGraphConnectionsEntityStruct>(target))
|
||||||
return false;
|
return false;
|
||||||
using var connStructMapper =
|
var connections = entitiesDB.QueryEntity<MachineGraphConnectionsEntityStruct>(target);
|
||||||
entitiesDB.QueryNativeMappedEntities<MachineGraphConnectionsEntityStruct>(GroupTag<BLOCK_TAG>.Groups,
|
var groups = entitiesDB.FindGroups<MachineGraphConnectionsEntityStruct>();
|
||||||
Svelto.Common.Allocator.Temp);
|
using var connStructMapper = //The allocator needs to be persistent because that's what is used in the Dispose() method
|
||||||
if (entitiesDB.TryQueryNativeMappedEntities<MachineConnectionComponent>(
|
entitiesDB.QueryNativeMappedEntities<MachineGraphConnectionsEntityStruct>(groups, Allocator.Persistent);
|
||||||
ConnectionsExclusiveGroups.MACHINE_CONNECTION_GROUP, out var mapper))
|
for (int i = connections.connections.Count<MachineConnectionStruct>() - 1; i >= 0; i--)
|
||||||
{
|
_connectionFactory.RemoveConnection(connections, i, connStructMapper);
|
||||||
BlockGroupUtility.RemoveBlockConnections(target, removedConnections, _connectionFactory,
|
|
||||||
connStructMapper, mapper, entitiesDB.GetEntityReferenceMap(), _entityFunctions);
|
|
||||||
}
|
|
||||||
|
|
||||||
_entityFunctions.RemoveEntity<BlockEntityDescriptor>(target);
|
_entityFunctions.RemoveEntity<BlockEntityDescriptor>(target);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Ready()
|
public void Ready()
|
||||||
{
|
{
|
||||||
removedConnections = new(2000, Allocator.Persistent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { get; set; }
|
public EntitiesDB entitiesDB { get; set; }
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
removedConnections.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name => "TechbloxModdingAPIRemovalGameEngine";
|
public string Name { get; } = "TechbloxModdingAPIRemovalGameEngine";
|
||||||
public string name => Name;
|
|
||||||
|
|
||||||
public bool isRemovable => false;
|
public bool isRemovable => false;
|
||||||
|
|
||||||
|
@ -75,12 +61,5 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
return AccessTools.TypeByName("RobocraftX.CR.MachineEditing.RemoveBlockEngine").GetConstructors()[0];
|
return AccessTools.TypeByName("RobocraftX.CR.MachineEditing.RemoveBlockEngine").GetConstructors()[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public JobHandle DeterministicStep(in float deltaTime, JobHandle inputDeps)
|
|
||||||
{
|
|
||||||
if (removedConnections.IsCreated)
|
|
||||||
removedConnections.Clear();
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,7 +7,6 @@ using UnityEngine;
|
||||||
|
|
||||||
using TechbloxModdingAPI.Engines;
|
using TechbloxModdingAPI.Engines;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
using TechbloxModdingAPI.Utility.ECS;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Blocks.Engines
|
namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
{
|
{
|
||||||
|
@ -41,7 +40,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
ref RotationEntityStruct rotStruct = ref this.entitiesDB.QueryEntityOrDefault<RotationEntityStruct>(block);
|
ref RotationEntityStruct rotStruct = ref this.entitiesDB.QueryEntityOrDefault<RotationEntityStruct>(block);
|
||||||
ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntityOrDefault<GridRotationStruct>(block);
|
ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntityOrDefault<GridRotationStruct>(block);
|
||||||
ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntityOrDefault<LocalTransformEntityStruct>(block);
|
ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntityOrDefault<LocalTransformEntityStruct>(block);
|
||||||
var phyStruct = this.entitiesDB.QueryEntityOptional<DOTSPhysicsEntityStruct>(block);
|
ref DOTSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntityOrDefault<DOTSPhysicsEntityStruct>(block);
|
||||||
// main (persistent) rotation
|
// main (persistent) rotation
|
||||||
Quaternion newRotation = rotStruct.rotation;
|
Quaternion newRotation = rotStruct.rotation;
|
||||||
newRotation.eulerAngles = vector;
|
newRotation.eulerAngles = vector;
|
||||||
|
@ -51,18 +50,16 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
// rendered rotation
|
// rendered rotation
|
||||||
transStruct.rotation = newRotation;
|
transStruct.rotation = newRotation;
|
||||||
// collision rotation
|
// collision rotation
|
||||||
if (phyStruct)
|
if (phyStruct.ID != default)
|
||||||
{ //It exists
|
{ //It exists
|
||||||
FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.Get().dotsEntity,
|
FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.dotsEntity,
|
||||||
new Unity.Transforms.Rotation
|
new Unity.Transforms.Rotation
|
||||||
{
|
{
|
||||||
Value = rotStruct.rotation
|
Value = rotStruct.rotation
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Connections probably need to be assigned (maybe)
|
entitiesDB.QueryEntityOrDefault<GridConnectionsEntityStruct>(block).isProcessed = false;
|
||||||
// They are assigned during machine processing anyway
|
|
||||||
entitiesDB.QueryEntityOrDefault<GridConnectionsEntityStruct>(block).areConnectionsAssigned = false;
|
|
||||||
return ((Quaternion)rotStruct.rotation).eulerAngles;
|
return ((Quaternion)rotStruct.rotation).eulerAngles;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ using Svelto.ECS;
|
||||||
|
|
||||||
using TechbloxModdingAPI.Engines;
|
using TechbloxModdingAPI.Engines;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
using TechbloxModdingAPI.Utility.ECS;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Blocks.Engines
|
namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
{
|
{
|
||||||
|
@ -42,7 +41,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
|
||||||
// implementations for block wiring
|
// implementations for block wiring
|
||||||
|
|
||||||
public (WireEntityStruct Wire, EGID ID) CreateNewWire(EGID startBlock, byte startPort, EGID endBlock, byte endPort)
|
public WireEntityStruct CreateNewWire(EGID startBlock, byte startPort, EGID endBlock, byte endPort)
|
||||||
{
|
{
|
||||||
EGID wireEGID = new EGID(BuildModeWiresGroups.NewWireEntityId, BuildModeWiresGroups.WiresGroup.Group);
|
EGID wireEGID = new EGID(BuildModeWiresGroups.NewWireEntityId, BuildModeWiresGroups.WiresGroup.Group);
|
||||||
EntityInitializer wireInitializer = Factory.BuildEntity<WireEntityDescriptor>(wireEGID);
|
EntityInitializer wireInitializer = Factory.BuildEntity<WireEntityDescriptor>(wireEGID);
|
||||||
|
@ -51,9 +50,10 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
sourceBlockEGID = startBlock,
|
sourceBlockEGID = startBlock,
|
||||||
sourcePortUsage = startPort,
|
sourcePortUsage = startPort,
|
||||||
destinationBlockEGID = endBlock,
|
destinationBlockEGID = endBlock,
|
||||||
destinationPortUsage = endPort
|
destinationPortUsage = endPort,
|
||||||
|
ID = wireEGID
|
||||||
});
|
});
|
||||||
return (wireInitializer.Get<WireEntityStruct>(), wireEGID);
|
return wireInitializer.Get<WireEntityStruct>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref WireEntityStruct GetWire(EGID wire)
|
public ref WireEntityStruct GetWire(EGID wire)
|
||||||
|
@ -116,8 +116,9 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
|
||||||
public bool SetSignal(uint signalID, float signal, bool input = true)
|
public bool SetSignal(uint signalID, float signal, bool input = true)
|
||||||
{
|
{
|
||||||
var (array, count) = GetSignalStruct(signalID, out uint index, input);
|
var array = GetSignalStruct(signalID, out uint index, input);
|
||||||
if (count > 0) array[index].valueAsFloat = signal;
|
var arrayB = array.ToBuffer();
|
||||||
|
if (array.count > 0) arrayB.buffer[index].valueAsFloat = signal;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,10 +130,11 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
|
||||||
public float AddSignal(uint signalID, float signal, bool clamp = true, bool input = true)
|
public float AddSignal(uint signalID, float signal, bool clamp = true, bool input = true)
|
||||||
{
|
{
|
||||||
var (array, count) = GetSignalStruct(signalID, out uint index, input);
|
var array = GetSignalStruct(signalID, out uint index, input);
|
||||||
if (count > 0)
|
var arrayB = array.ToBuffer();
|
||||||
|
if (array.count > 0)
|
||||||
{
|
{
|
||||||
ref var channelData = ref array[index];
|
ref var channelData = ref arrayB.buffer[index];
|
||||||
channelData.valueAsFloat += signal;
|
channelData.valueAsFloat += signal;
|
||||||
if (clamp)
|
if (clamp)
|
||||||
{
|
{
|
||||||
|
@ -160,8 +162,9 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
|
||||||
public float GetSignal(uint signalID, bool input = true)
|
public float GetSignal(uint signalID, bool input = true)
|
||||||
{
|
{
|
||||||
var (array, count) = GetSignalStruct(signalID, out uint index, input);
|
var array = GetSignalStruct(signalID, out uint index, input);
|
||||||
return count > 0 ? array[index].valueAsFloat : 0f;
|
var arrayB = array.ToBuffer();
|
||||||
|
return array.count > 0 ? arrayB.buffer[index].valueAsFloat : 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint[] GetSignalIDs(EGID blockID, bool input = true)
|
public uint[] GetSignalIDs(EGID blockID, bool input = true)
|
||||||
|
@ -226,27 +229,28 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
uint entityID = (output ? ports.firstOutputID : ports.firstInputID) + i;
|
uint entityID = (output ? ports.firstOutputID : ports.firstInputID) + i;
|
||||||
if (!mapper.TryGetArrayAndEntityIndex(entityID, out var index, out var array) ||
|
if (!mapper.TryGetArrayAndEntityIndex(entityID, out var index, out var array) ||
|
||||||
array[index].usage != portUsage) continue;
|
array[index].usage != portUsage) continue;
|
||||||
return new OptionalRef<PortEntityStruct>(array, index, new EGID(entityID, group));
|
return new OptionalRef<PortEntityStruct>(array, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OptionalRef<WireEntityStruct> MatchPortToWire(PortEntityStruct port, EGID blockID, out EGID wireID)
|
public ref WireEntityStruct MatchPortToWire(PortEntityStruct port, EGID blockID, out bool exists)
|
||||||
{
|
{
|
||||||
var (wires, ids, count) = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group);
|
var wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group);
|
||||||
for (uint i = 0; i < count; i++)
|
var wiresB = wires.ToBuffer().buffer;
|
||||||
|
for (uint i = 0; i < wires.count; i++)
|
||||||
{
|
{
|
||||||
if ((wires[i].destinationPortUsage == port.usage && wires[i].destinationBlockEGID == blockID)
|
if ((wiresB[i].destinationPortUsage == port.usage && wiresB[i].destinationBlockEGID == blockID)
|
||||||
|| (wires[i].sourcePortUsage == port.usage && wires[i].sourceBlockEGID == blockID))
|
|| (wiresB[i].sourcePortUsage == port.usage && wiresB[i].sourceBlockEGID == blockID))
|
||||||
{
|
{
|
||||||
wireID = new EGID(ids[i], BuildModeWiresGroups.WiresGroup.Group);
|
exists = true;
|
||||||
return new OptionalRef<WireEntityStruct>(wires, i);
|
return ref wiresB[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
exists = false;
|
||||||
wireID = default;
|
WireEntityStruct[] defRef = new WireEntityStruct[1];
|
||||||
return default;
|
return ref defRef[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public EGID MatchBlocksToWire(EGID startBlock, EGID endBlock, byte startPort = byte.MaxValue, byte endPort = byte.MaxValue)
|
public EGID MatchBlocksToWire(EGID startBlock, EGID endBlock, byte startPort = byte.MaxValue, byte endPort = byte.MaxValue)
|
||||||
|
@ -275,20 +279,20 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
endPorts = new EGID[] {new EGID(ports.firstInputID + endPort, NamedExclusiveGroup<BuildModeWiresGroups.InputPortsGroup>.Group) };
|
endPorts = new EGID[] {new EGID(ports.firstInputID + endPort, NamedExclusiveGroup<BuildModeWiresGroups.InputPortsGroup>.Group) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EntityCollection<WireEntityStruct> wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group);
|
||||||
|
var wiresB = wires.ToBuffer().buffer;
|
||||||
for (int endIndex = 0; endIndex < endPorts.Length; endIndex++)
|
for (int endIndex = 0; endIndex < endPorts.Length; endIndex++)
|
||||||
{
|
{
|
||||||
PortEntityStruct endPES = entitiesDB.QueryEntity<PortEntityStruct>(endPorts[endIndex]);
|
PortEntityStruct endPES = entitiesDB.QueryEntity<PortEntityStruct>(endPorts[endIndex]);
|
||||||
for (int startIndex = 0; startIndex < startPorts.Length; startIndex++)
|
for (int startIndex = 0; startIndex < startPorts.Length; startIndex++)
|
||||||
{
|
{
|
||||||
PortEntityStruct startPES = entitiesDB.QueryEntity<PortEntityStruct>(startPorts[startIndex]);
|
PortEntityStruct startPES = entitiesDB.QueryEntity<PortEntityStruct>(startPorts[startIndex]);
|
||||||
foreach (var wireOpt in entitiesDB.QueryEntitiesOptional<WireEntityStruct>(
|
for (int w = 0; w < wires.count; w++)
|
||||||
NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group))
|
|
||||||
{
|
{
|
||||||
var wire = wireOpt.Get();
|
if ((wiresB[w].destinationPortUsage == endPES.usage && wiresB[w].destinationBlockEGID == endBlock)
|
||||||
if ((wire.destinationPortUsage == endPES.usage && wire.destinationBlockEGID == endBlock)
|
&& (wiresB[w].sourcePortUsage == startPES.usage && wiresB[w].sourceBlockEGID == startBlock))
|
||||||
&& (wire.sourcePortUsage == startPES.usage && wire.sourceBlockEGID == startBlock))
|
|
||||||
{
|
{
|
||||||
return wireOpt.EGID;
|
return wiresB[w].ID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -300,21 +304,23 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
public OptionalRef<ChannelDataStruct> GetChannelDataStruct(EGID portID)
|
public OptionalRef<ChannelDataStruct> GetChannelDataStruct(EGID portID)
|
||||||
{
|
{
|
||||||
var port = GetPort(portID);
|
var port = GetPort(portID);
|
||||||
var (channels, count) = entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<BuildModeWiresGroups.ChannelDataGroup>.Group);
|
var channels = entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<BuildModeWiresGroups.ChannelDataGroup>.Group);
|
||||||
return port.firstChannelIndexCachedInSim < count
|
var channelsB = channels.ToBuffer();
|
||||||
? new OptionalRef<ChannelDataStruct>(channels, port.firstChannelIndexCachedInSim)
|
return port.firstChannelIndexCachedInSim < channels.count
|
||||||
|
? new OptionalRef<ChannelDataStruct>(channelsB.buffer, port.firstChannelIndexCachedInSim)
|
||||||
: default;
|
: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EGID[] GetElectricBlocks()
|
public EGID[] GetElectricBlocks()
|
||||||
{
|
{
|
||||||
var res = new FasterList<EGID>();
|
var res = new FasterList<EGID>();
|
||||||
foreach (var ((coll, ids, count), _) in entitiesDB.QueryEntities<BlockPortsStruct>())
|
foreach (var (coll, _) in entitiesDB.QueryEntities<BlockPortsStruct>())
|
||||||
{
|
{
|
||||||
for (int i = 0; i < count; i++)
|
var collB = coll.ToBuffer();
|
||||||
|
for (int i = 0; i < coll.count; i++)
|
||||||
{
|
{
|
||||||
ref BlockPortsStruct s = ref coll[i];
|
ref BlockPortsStruct s = ref collB.buffer[i];
|
||||||
//res.Add(s.ID); - TODO: Would need to search for the groups for each block
|
res.Add(s.ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,18 +329,43 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
|
|
||||||
public EGID[] WiredToInput(EGID block, byte port)
|
public EGID[] WiredToInput(EGID block, byte port)
|
||||||
{
|
{
|
||||||
return entitiesDB
|
WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group,
|
||||||
.QueryEntitiesOptional<WireEntityStruct>(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group)
|
(WireEntityStruct wes) => wes.destinationPortUsage == port && wes.destinationBlockEGID == block);
|
||||||
.ToArray(wire => wire.ID,
|
EGID[] result = new EGID[wireEntityStructs.Length];
|
||||||
wire => wire.Component.destinationPortUsage == port && wire.Component.destinationBlockEGID == block);
|
for (uint i = 0; i < wireEntityStructs.Length; i++)
|
||||||
|
{
|
||||||
|
result[i] = wireEntityStructs[i].ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EGID[] WiredToOutput(EGID block, byte port)
|
public EGID[] WiredToOutput(EGID block, byte port)
|
||||||
{
|
{
|
||||||
return entitiesDB
|
WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group,
|
||||||
.QueryEntitiesOptional<WireEntityStruct>(NamedExclusiveGroup<BuildModeWiresGroups.WiresGroup>.Group)
|
(WireEntityStruct wes) => wes.sourcePortUsage == port && wes.sourceBlockEGID == block);
|
||||||
.ToArray(wire => wire.ID,
|
EGID[] result = new EGID[wireEntityStructs.Length];
|
||||||
wire => wire.Component.sourcePortUsage == port && wire.Component.sourceBlockEGID == block);
|
for (uint i = 0; i < wireEntityStructs.Length; i++)
|
||||||
|
{
|
||||||
|
result[i] = wireEntityStructs[i].ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private T[] Search<T>(ExclusiveGroup group, Func<T, bool> isMatch) where T : unmanaged, IEntityComponent
|
||||||
|
{
|
||||||
|
FasterList<T> results = new FasterList<T>();
|
||||||
|
EntityCollection<T> components = entitiesDB.QueryEntities<T>(group);
|
||||||
|
var componentsB = components.ToBuffer();
|
||||||
|
for (uint i = 0; i < components.count; i++)
|
||||||
|
{
|
||||||
|
if (isMatch(componentsB.buffer[i]))
|
||||||
|
{
|
||||||
|
results.Add(componentsB.buffer[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private EntityCollection<ChannelDataStruct> GetSignalStruct(uint signalID, out uint index, bool input = true)
|
private EntityCollection<ChannelDataStruct> GetSignalStruct(uint signalID, out uint index, bool input = true)
|
||||||
|
@ -344,7 +375,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
|
||||||
: NamedExclusiveGroup<BuildModeWiresGroups.OutputPortsGroup>.Group;
|
: NamedExclusiveGroup<BuildModeWiresGroups.OutputPortsGroup>.Group;
|
||||||
if (entitiesDB.Exists<PortEntityStruct>(signalID, group))
|
if (entitiesDB.Exists<PortEntityStruct>(signalID, group))
|
||||||
{
|
{
|
||||||
index = entitiesDB.QueryEntity<PortEntityStruct>(signalID, group).firstChannelIndexCachedInSim;
|
index = entitiesDB.QueryEntity<PortEntityStruct>(signalID, group).anyChannelIndex;
|
||||||
var channelData =
|
var channelData =
|
||||||
entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<BuildModeWiresGroups.ChannelDataGroup>.Group);
|
entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<BuildModeWiresGroups.ChannelDataGroup>.Group);
|
||||||
return channelData;
|
return channelData;
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
using System;
|
|
||||||
using Techblox.ObjectIDBlockServer;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Blocks
|
|
||||||
{
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
|
|
||||||
public class ObjectID : SignalingBlock
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs a(n) ObjectID object representing an existing block.
|
|
||||||
/// </summary>
|
|
||||||
public ObjectID(EGID egid) :
|
|
||||||
base(egid)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs a(n) ObjectID object representing an existing block.
|
|
||||||
/// </summary>
|
|
||||||
public ObjectID(uint id) :
|
|
||||||
base(new EGID(id, ObjectIDBlockExclusiveGroups.OBJECT_ID_BLOCK_GROUP))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the ObjectID's Identifier property. Tweakable stat.
|
|
||||||
/// </summary>
|
|
||||||
public char Identifier
|
|
||||||
{
|
|
||||||
get => (char) (BlockEngine.GetBlockInfo<ObjectIDTweakableComponent>(this).objectIDToTrigger + 'A');
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if(value is < 'A' or > 'Z')
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(value), "ObjectIdentifier must be set to a letter between A and Z.");
|
|
||||||
BlockEngine.GetBlockInfo<ObjectIDTweakableComponent>(this).objectIDToTrigger = (byte) (value - 'A');
|
|
||||||
Label = value + ""; //The label isn't updated automatically
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Finds the identifier 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 ObjectID[] GetByID(char id) => BlockEngine.GetObjectIDsFromID((byte) (id - 'A'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -30,11 +30,11 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return BlockEngine.GetBlockInfo<Techblox.ServoBlocksServer.ServoReadOnlyTweakableComponent>(this).servoVelocity;
|
return BlockEngine.GetBlockInfo<RobocraftX.Blocks.ServoReadOnlyStruct>(this).servoVelocity;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
BlockEngine.GetBlockInfo<Techblox.ServoBlocksServer.ServoReadOnlyTweakableComponent>(this).servoVelocity = value;
|
BlockEngine.GetBlockInfo<RobocraftX.Blocks.ServoReadOnlyStruct>(this).servoVelocity = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,11 +45,11 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return BlockEngine.GetBlockInfo<Techblox.ServoBlocksServer.ServoReadOnlyTweakableComponent>(this).minDeviation;
|
return BlockEngine.GetBlockInfo<RobocraftX.Blocks.ServoReadOnlyStruct>(this).minDeviation;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
BlockEngine.GetBlockInfo<Techblox.ServoBlocksServer.ServoReadOnlyTweakableComponent>(this).minDeviation = value;
|
BlockEngine.GetBlockInfo<RobocraftX.Blocks.ServoReadOnlyStruct>(this).minDeviation = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,11 +60,11 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return BlockEngine.GetBlockInfo<Techblox.ServoBlocksServer.ServoReadOnlyTweakableComponent>(this).maxDeviation;
|
return BlockEngine.GetBlockInfo<RobocraftX.Blocks.ServoReadOnlyStruct>(this).maxDeviation;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
BlockEngine.GetBlockInfo<Techblox.ServoBlocksServer.ServoReadOnlyTweakableComponent>(this).maxDeviation = value;
|
BlockEngine.GetBlockInfo<RobocraftX.Blocks.ServoReadOnlyStruct>(this).maxDeviation = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,11 +75,11 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return BlockEngine.GetBlockInfo<Techblox.ServoBlocksServer.ServoReadOnlyTweakableComponent>(this).reverse;
|
return BlockEngine.GetBlockInfo<RobocraftX.Blocks.ServoReadOnlyStruct>(this).reverse;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
BlockEngine.GetBlockInfo<Techblox.ServoBlocksServer.ServoReadOnlyTweakableComponent>(this).reverse = value;
|
BlockEngine.GetBlockInfo<RobocraftX.Blocks.ServoReadOnlyStruct>(this).reverse = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,11 +90,11 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return BlockEngine.GetBlockInfo<Techblox.ServoBlocksServer.ServoReadOnlyTweakableComponent>(this).hasProportionalInput;
|
return BlockEngine.GetBlockInfo<RobocraftX.Blocks.ServoReadOnlyStruct>(this).hasProportionalInput;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
BlockEngine.GetBlockInfo<Techblox.ServoBlocksServer.ServoReadOnlyTweakableComponent>(this).hasProportionalInput = value;
|
BlockEngine.GetBlockInfo<RobocraftX.Blocks.ServoReadOnlyStruct>(this).hasProportionalInput = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,11 +105,11 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return BlockEngine.GetBlockInfo<Techblox.ServoBlocksServer.ServoReadOnlyTweakableComponent>(this).directionVector;
|
return BlockEngine.GetBlockInfo<RobocraftX.Blocks.ServoReadOnlyStruct>(this).directionVector;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
BlockEngine.GetBlockInfo<Techblox.ServoBlocksServer.ServoReadOnlyTweakableComponent>(this).directionVector = value;
|
BlockEngine.GetBlockInfo<RobocraftX.Blocks.ServoReadOnlyStruct>(this).directionVector = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,11 +120,11 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return BlockEngine.GetBlockInfo<Techblox.ServoBlocksServer.ServoReadOnlyTweakableComponent>(this).rotationAxis;
|
return BlockEngine.GetBlockInfo<RobocraftX.Blocks.ServoReadOnlyStruct>(this).rotationAxis;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
BlockEngine.GetBlockInfo<Techblox.ServoBlocksServer.ServoReadOnlyTweakableComponent>(this).rotationAxis = value;
|
BlockEngine.GetBlockInfo<RobocraftX.Blocks.ServoReadOnlyStruct>(this).rotationAxis = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,11 +135,11 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return BlockEngine.GetBlockInfo<Techblox.ServoBlocksServer.ServoReadOnlyTweakableComponent>(this).forceAxis;
|
return BlockEngine.GetBlockInfo<RobocraftX.Blocks.ServoReadOnlyStruct>(this).forceAxis;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
BlockEngine.GetBlockInfo<Techblox.ServoBlocksServer.ServoReadOnlyTweakableComponent>(this).forceAxis = value;
|
BlockEngine.GetBlockInfo<RobocraftX.Blocks.ServoReadOnlyStruct>(this).forceAxis = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,9 +46,9 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
/// <returns>The connected wire.</returns>
|
/// <returns>The connected wire.</returns>
|
||||||
/// <param name="portId">Port identifier.</param>
|
/// <param name="portId">Port identifier.</param>
|
||||||
/// <param name="connected">Whether the port has a wire connected to it.</param>
|
/// <param name="connected">Whether the port has a wire connected to it.</param>
|
||||||
protected OptionalRef<WireEntityStruct> GetConnectedWire(PortEntityStruct port, out EGID egid)
|
protected ref WireEntityStruct GetConnectedWire(PortEntityStruct port, out bool connected)
|
||||||
{
|
{
|
||||||
return SignalEngine.MatchPortToWire(port, Id, out egid);
|
return ref SignalEngine.MatchPortToWire(port, Id, out connected);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -40,21 +40,6 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the WheelRig's FlipDirection property. Tweakable stat.
|
|
||||||
/// </summary>
|
|
||||||
public bool FlipDirection
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BlockEngine.GetBlockInfo<Techblox.WheelRigBlock.WheelRigTweakableStruct>(this).flipDirection;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
BlockEngine.GetBlockInfo<Techblox.WheelRigBlock.WheelRigTweakableStruct>(this).flipDirection = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the WheelRig's MaxVelocity property. May not be saved.
|
/// Gets or sets the WheelRig's MaxVelocity property. May not be saved.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -86,22 +71,6 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the WheelRig's FlipSteering property. Tweakable stat.
|
|
||||||
/// </summary>
|
|
||||||
[TestValue(false)]
|
|
||||||
public bool FlipSteering
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BlockEngine.GetBlockInfo<Techblox.WheelRigBlock.WheelRigSteerableTweakableStruct>(this).flipSteering;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
BlockEngine.GetBlockInfo<Techblox.WheelRigBlock.WheelRigSteerableTweakableStruct>(this).flipSteering = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the WheelRig's VelocityForMinAngle property. May not be saved.
|
/// Gets or sets the WheelRig's VelocityForMinAngle property. May not be saved.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -5,7 +5,6 @@ using Svelto.ECS;
|
||||||
using Svelto.ECS.Experimental;
|
using Svelto.ECS.Experimental;
|
||||||
|
|
||||||
using TechbloxModdingAPI.Blocks.Engines;
|
using TechbloxModdingAPI.Blocks.Engines;
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Blocks
|
namespace TechbloxModdingAPI.Blocks
|
||||||
{
|
{
|
||||||
|
@ -31,8 +30,8 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
|
|
||||||
public static Wire Connect(SignalingBlock start, byte startPort, SignalingBlock end, byte endPort)
|
public static Wire Connect(SignalingBlock start, byte startPort, SignalingBlock end, byte endPort)
|
||||||
{
|
{
|
||||||
var (wire, id) = signalEngine.CreateNewWire(start.Id, startPort, end.Id, endPort);
|
WireEntityStruct wire = signalEngine.CreateNewWire(start.Id, startPort, end.Id, endPort);
|
||||||
return new Wire(wire, start, end, id);
|
return new Wire(wire, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -46,9 +45,9 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
{
|
{
|
||||||
var port = signalEngine.MatchBlockIOToPort(end, endPort, false);
|
var port = signalEngine.MatchBlockIOToPort(end, endPort, false);
|
||||||
if (!port) return null;
|
if (!port) return null;
|
||||||
var wire = signalEngine.MatchPortToWire(port, end.Id, out var egid);
|
WireEntityStruct wire = signalEngine.MatchPortToWire(port, end.Id, out var exists);
|
||||||
return wire
|
return exists
|
||||||
? new Wire(wire.Get().sourceBlockEGID, end.Id, wire.Get().sourcePortUsage, endPort, egid, false)
|
? new Wire(wire.sourceBlockEGID, end.Id, wire.sourcePortUsage, endPort, wire.ID, false)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,9 +62,9 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
{
|
{
|
||||||
var port = signalEngine.MatchBlockIOToPort(start, startPort, true);
|
var port = signalEngine.MatchBlockIOToPort(start, startPort, true);
|
||||||
if (!port) return null;
|
if (!port) return null;
|
||||||
var wire = signalEngine.MatchPortToWire(port, start.Id, out var egid);
|
WireEntityStruct wire = signalEngine.MatchPortToWire(port, start.Id, out var exists);
|
||||||
return wire
|
return exists
|
||||||
? new Wire(start.Id, wire.Get().destinationBlockEGID, startPort, wire.Get().destinationPortUsage, egid, false)
|
? new Wire(start.Id, wire.destinationBlockEGID, startPort, wire.destinationPortUsage, wire.ID, false)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,9 +132,9 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
this.endBlockEGID = endBlock;
|
this.endBlockEGID = endBlock;
|
||||||
this.inputToOutput = inputToOutput;
|
this.inputToOutput = inputToOutput;
|
||||||
this.wireEGID = wire;
|
this.wireEGID = wire;
|
||||||
endPortEGID = signalEngine.MatchBlockIOToPort(startBlock, startPort, inputToOutput).EGID;
|
endPortEGID = signalEngine.MatchBlockIOToPort(startBlock, startPort, inputToOutput).Nullable()?.ID ?? default;
|
||||||
if (endPortEGID == default) throw new WireInvalidException("Wire end port not found");
|
if (endPortEGID == default) throw new WireInvalidException("Wire end port not found");
|
||||||
startPortEGID = signalEngine.MatchBlockIOToPort(endBlock, endPort, !inputToOutput).EGID;
|
startPortEGID = signalEngine.MatchBlockIOToPort(endBlock, endPort, !inputToOutput).Nullable()?.ID ?? default;
|
||||||
if (startPortEGID == default) throw new WireInvalidException("Wire start port not found");
|
if (startPortEGID == default) throw new WireInvalidException("Wire start port not found");
|
||||||
this.startPort = startPort;
|
this.startPort = startPort;
|
||||||
this.endPort = endPort;
|
this.endPort = endPort;
|
||||||
|
@ -152,8 +151,8 @@ namespace TechbloxModdingAPI.Blocks
|
||||||
wireEgid, false);
|
wireEgid, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Wire(WireEntityStruct wire, SignalingBlock src, SignalingBlock dest, EGID wireEgid)
|
private Wire(WireEntityStruct wire, SignalingBlock src, SignalingBlock dest)
|
||||||
: this(src, dest, wire.sourcePortUsage, wire.destinationPortUsage, wireEgid, false)
|
: this(src, dest, wire.sourcePortUsage, wire.destinationPortUsage, wire.ID, false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using Svelto.ECS;
|
using Gamecraft.Damage;
|
||||||
using Techblox.TimeRunning.Clusters;
|
using RobocraftX.Common;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI
|
namespace TechbloxModdingAPI
|
||||||
{
|
{
|
||||||
|
@ -13,33 +14,28 @@ namespace TechbloxModdingAPI
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public Cluster(uint id) : this(new EGID(id, ClustersExclusiveGroups.SIMULATION_CLUSTERS_GROUP))
|
public Cluster(uint id) : this(new EGID(id, CommonExclusiveGroups.SIMULATION_CLUSTERS_GROUP))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public float InitialHealth //TODO
|
public float InitialHealth
|
||||||
{
|
{
|
||||||
get => 0f;
|
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).initialHealth;
|
||||||
set { }
|
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).initialHealth = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float CurrentHealth
|
public float CurrentHealth
|
||||||
{
|
{
|
||||||
get => 0f;
|
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).currentHealth;
|
||||||
set { }
|
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).currentHealth = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float HealthMultiplier
|
public float HealthMultiplier
|
||||||
{
|
{
|
||||||
get => 0f;
|
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).healthMultiplier;
|
||||||
set { }
|
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).healthMultiplier = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The mass of the cluster.
|
|
||||||
/// </summary>
|
|
||||||
public float Mass => Block.BlockEngine.GetBlockInfo<ClusterMassComponent>(this).mass;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the simulation-time rigid bodies for the chunks in this cluster.
|
/// Returns the simulation-time rigid bodies for the chunks in this cluster.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -62,13 +62,6 @@ namespace TechbloxModdingAPI
|
||||||
var id = initializer(this);
|
var id = initializer(this);
|
||||||
if (!dict.ContainsKey(id)) // Multiple instances may be created
|
if (!dict.ContainsKey(id)) // Multiple instances may be created
|
||||||
dict.Add(id, this);
|
dict.Add(id, this);
|
||||||
else
|
|
||||||
{
|
|
||||||
Logging.MetaDebugLog($"An object of this type and ID is already stored: {GetType()} - {id}");
|
|
||||||
Logging.MetaDebugLog(this);
|
|
||||||
Logging.MetaDebugLog(dict[id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Id = id;
|
Id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace TechbloxModdingAPI.Engines
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Engine interface to handle ModEventEntityStruct events emitted by IEventEmitterEngines.
|
/// Engine interface to handle ModEventEntityStruct events emitted by IEventEmitterEngines.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IReactionaryEngine<T> : IApiEngine, IReactOnAddAndRemove<T> where T : unmanaged, IEntityComponent
|
public interface IReactionaryEngine<T> : IApiEngine, IReactOnAddAndRemove<T>, IReactOnAddAndRemove where T : unmanaged, IEntityComponent
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace TechbloxModdingAPI.Input
|
||||||
|
|
||||||
public static MethodBase TargetMethod()
|
public static MethodBase TargetMethod()
|
||||||
{
|
{
|
||||||
return AccessTools.Method("RobocraftX.Multiplayer.Input.DeterministicInputRecorderEngine:RecordDeterministicInput");
|
return AccessTools.Method("RobocraftX.Multiplayer.Input.NetworkInputRecorderEngine:RecordDeterministicInput");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -24,7 +24,7 @@ namespace TechbloxModdingAPI.Interface.IMGUI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<bool> OnClick;
|
public event EventHandler<bool> OnClick;
|
||||||
|
|
||||||
public override void OnGUI()
|
public void OnGUI()
|
||||||
{
|
{
|
||||||
if (automaticLayout)
|
if (automaticLayout)
|
||||||
{
|
{
|
||||||
|
@ -42,15 +42,34 @@ namespace TechbloxModdingAPI.Interface.IMGUI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The button's unique name.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to display the button.
|
||||||
|
/// </summary>
|
||||||
|
public bool Enabled { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize a new button with automatic layout.
|
/// Initialize a new button with automatic layout.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="text">The text to display on the button.</param>
|
/// <param name="text">The text to display on the button.</param>
|
||||||
/// <param name="name">The button's name.</param>
|
/// <param name="name">The button's name.</param>
|
||||||
public Button(string text, string name = null) : base(text, name)
|
public Button(string text, string name = null)
|
||||||
{
|
{
|
||||||
automaticLayout = true;
|
automaticLayout = true;
|
||||||
this.text = text;
|
this.text = text;
|
||||||
|
if (name == null)
|
||||||
|
{
|
||||||
|
this.Name = typeof(Button).FullName + "::" + text;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.Name = name;
|
||||||
|
}
|
||||||
|
IMGUIManager.AddElement(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -64,5 +83,10 @@ namespace TechbloxModdingAPI.Interface.IMGUI
|
||||||
automaticLayout = false;
|
automaticLayout = false;
|
||||||
this.Box = box;
|
this.Box = box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~Button()
|
||||||
|
{
|
||||||
|
IMGUIManager.RemoveElement(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,7 +20,7 @@ namespace TechbloxModdingAPI.Interface.IMGUI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Rect Box { get; set; }
|
public Rect Box { get; set; }
|
||||||
|
|
||||||
public override void OnGUI()
|
public void OnGUI()
|
||||||
{
|
{
|
||||||
/*if (Constants.Default == null) return;
|
/*if (Constants.Default == null) return;
|
||||||
if (Constants.Default.box == null) return;*/
|
if (Constants.Default.box == null) return;*/
|
||||||
|
@ -61,6 +61,16 @@ namespace TechbloxModdingAPI.Interface.IMGUI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The group's unique name.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to display the group and everything in it.
|
||||||
|
/// </summary>
|
||||||
|
public bool Enabled { set; get; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The amount of elements in the group.
|
/// The amount of elements in the group.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -75,10 +85,19 @@ namespace TechbloxModdingAPI.Interface.IMGUI
|
||||||
/// <param name="box">The rectangular area to use in the window.</param>
|
/// <param name="box">The rectangular area to use in the window.</param>
|
||||||
/// <param name="name">Name of the group.</param>
|
/// <param name="name">Name of the group.</param>
|
||||||
/// <param name="automaticLayout">Whether to use automatic UI layout.</param>
|
/// <param name="automaticLayout">Whether to use automatic UI layout.</param>
|
||||||
public Group(Rect box, string name = null, bool automaticLayout = false) : base(box.ToString().Replace(" ", ""), name)
|
public Group(Rect box, string name = null, bool automaticLayout = false)
|
||||||
{
|
{
|
||||||
Box = box;
|
Box = box;
|
||||||
|
if (name == null)
|
||||||
|
{
|
||||||
|
this.Name = typeof(Group).FullName + "::" + box.ToString().Replace(" ", "");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.Name = name;
|
||||||
|
}
|
||||||
this.automaticLayout = automaticLayout;
|
this.automaticLayout = automaticLayout;
|
||||||
|
IMGUIManager.AddElement(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -2,7 +2,6 @@ using System.Collections.Generic;
|
||||||
using Svelto.Tasks;
|
using Svelto.Tasks;
|
||||||
using Svelto.Tasks.ExtraLean;
|
using Svelto.Tasks.ExtraLean;
|
||||||
using TechbloxModdingAPI.Tasks;
|
using TechbloxModdingAPI.Tasks;
|
||||||
using TechbloxModdingAPI.Utility;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Interface.IMGUI
|
namespace TechbloxModdingAPI.Interface.IMGUI
|
||||||
|
@ -15,9 +14,9 @@ namespace TechbloxModdingAPI.Interface.IMGUI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class IMGUIManager
|
public static class IMGUIManager
|
||||||
{
|
{
|
||||||
internal static OnGuiRunner ImguiScheduler = new("TechbloxModdingAPI_IMGUIScheduler");
|
internal static OnGuiRunner ImguiScheduler = new OnGuiRunner("TechbloxModdingAPI_IMGUIScheduler");
|
||||||
|
|
||||||
private static readonly WeakDictionary<string, UIElement> _activeElements = new();
|
private static Dictionary<string, UIElement> _activeElements = new Dictionary<string,UIElement>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add an UIElement instance to be managed by IMGUIManager.
|
/// Add an UIElement instance to be managed by IMGUIManager.
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace TechbloxModdingAPI.Interface.IMGUI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Rect Box { get; set; } = Rect.zero;
|
public Rect Box { get; set; } = Rect.zero;
|
||||||
|
|
||||||
public override void OnGUI()
|
public void OnGUI()
|
||||||
{
|
{
|
||||||
//if (Texture == null) return;
|
//if (Texture == null) return;
|
||||||
if (automaticLayout)
|
if (automaticLayout)
|
||||||
|
@ -33,15 +33,42 @@ namespace TechbloxModdingAPI.Interface.IMGUI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The image element's unique name.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to display the image and everything in it.
|
||||||
|
/// </summary>
|
||||||
|
public bool Enabled { set; get; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="T:TechbloxModdingAPI.Interface.IMGUI.Image"/> class with automatic layout.
|
/// Initializes a new instance of the <see cref="T:TechbloxModdingAPI.Interface.IMGUI.Image"/> class with automatic layout.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="texture">Image to display.</param>
|
/// <param name="texture">Image to display.</param>
|
||||||
/// <param name="name">The element's name.</param>
|
/// <param name="name">The element's name.</param>
|
||||||
public Image(Texture texture = null, string name = null) : base(texture == null ? "" : $"{texture.name}({texture.width}x{texture.height})", name)
|
public Image(Texture texture = null, string name = null)
|
||||||
{
|
{
|
||||||
automaticLayout = true;
|
automaticLayout = true;
|
||||||
Texture = texture;
|
Texture = texture;
|
||||||
|
if (name == null)
|
||||||
|
{
|
||||||
|
if (texture == null)
|
||||||
|
{
|
||||||
|
this.Name = typeof(Image).FullName + "::" + texture;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.Name = typeof(Image).FullName + "::" + texture.name + "(" + texture.width + "x" + texture.height + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.Name = name;
|
||||||
|
}
|
||||||
|
IMGUIManager.AddElement(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace TechbloxModdingAPI.Interface.IMGUI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Rect Box { get; set; } = Rect.zero;
|
public Rect Box { get; set; } = Rect.zero;
|
||||||
|
|
||||||
public override void OnGUI()
|
public void OnGUI()
|
||||||
{
|
{
|
||||||
if (automaticLayout)
|
if (automaticLayout)
|
||||||
{
|
{
|
||||||
|
@ -32,15 +32,34 @@ namespace TechbloxModdingAPI.Interface.IMGUI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The label's unique name.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to display the label.
|
||||||
|
/// </summary>
|
||||||
|
public bool Enabled { set; get; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="T:TechbloxModdingAPI.Interface.IMGUI.Label"/> class with automatic layout.
|
/// Initializes a new instance of the <see cref="T:TechbloxModdingAPI.Interface.IMGUI.Label"/> class with automatic layout.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="initialText">Initial string to display on the label.</param>
|
/// <param name="initialText">Initial string to display on the label.</param>
|
||||||
/// <param name="name">The element's name.</param>
|
/// <param name="name">The element's name.</param>
|
||||||
public Label(string initialText = null, string name = null) : base(initialText, name)
|
public Label(string initialText = null, string name = null)
|
||||||
{
|
{
|
||||||
automaticLayout = true;
|
automaticLayout = true;
|
||||||
Text = initialText;
|
Text = initialText;
|
||||||
|
if (name == null)
|
||||||
|
{
|
||||||
|
this.Name = typeof(Label).FullName + "::" + initialText;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.Name = name;
|
||||||
|
}
|
||||||
|
IMGUIManager.AddElement(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace TechbloxModdingAPI.Interface.IMGUI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<string> OnEdit;
|
public event EventHandler<string> OnEdit;
|
||||||
|
|
||||||
public override void OnGUI()
|
public void OnGUI()
|
||||||
{
|
{
|
||||||
string editedText = null;
|
string editedText = null;
|
||||||
if (automaticLayout)
|
if (automaticLayout)
|
||||||
|
@ -61,17 +61,36 @@ namespace TechbloxModdingAPI.Interface.IMGUI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The text field's unique name.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to display the text field.
|
||||||
|
/// </summary>
|
||||||
|
public bool Enabled { set; get; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize the text input field with automatic layout.
|
/// Initialize the text input field with automatic layout.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="initialText">Initial text in the input field.</param>
|
/// <param name="initialText">Initial text in the input field.</param>
|
||||||
/// <param name="name">The text field's name.</param>
|
/// <param name="name">The text field's name.</param>
|
||||||
/// <param name="multiline">Allow multiple lines?</param>
|
/// <param name="multiline">Allow multiple lines?</param>
|
||||||
public Text(string initialText = null, string name = null, bool multiline = false) : base(initialText, name)
|
public Text(string initialText = null, string name = null, bool multiline = false)
|
||||||
{
|
{
|
||||||
this.Multiline = multiline;
|
this.Multiline = multiline;
|
||||||
automaticLayout = true;
|
automaticLayout = true;
|
||||||
text = initialText ?? "";
|
text = initialText ?? "";
|
||||||
|
if (name == null)
|
||||||
|
{
|
||||||
|
this.Name = typeof(Text).FullName + "::" + text;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.Name = name;
|
||||||
|
}
|
||||||
|
IMGUIManager.AddElement(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -6,34 +6,23 @@ namespace TechbloxModdingAPI.Interface.IMGUI
|
||||||
/// GUI Element like a text field, button or picture.
|
/// GUI Element like a text field, button or picture.
|
||||||
/// This interface is used to wrap many elements from Unity's IMGUI system.
|
/// This interface is used to wrap many elements from Unity's IMGUI system.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class UIElement
|
public interface UIElement
|
||||||
{
|
{
|
||||||
protected UIElement(string text, string name)
|
|
||||||
{
|
|
||||||
Name = name ?? GetType().FullName + "::" + text;
|
|
||||||
IMGUIManager.AddElement(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
~UIElement()
|
|
||||||
{
|
|
||||||
IMGUIManager.RemoveElement(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// GUI operations to perform in the OnGUI scope.
|
/// GUI operations to perform in the OnGUI scope.
|
||||||
/// This is basically equivalent to a MonoBehaviour's OnGUI method.
|
/// This is basically equivalent to a MonoBehaviour's OnGUI method.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract void OnGUI();
|
void OnGUI();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The element's name.
|
/// The element's name.
|
||||||
/// This should be unique for every instance of the class.
|
/// This should be unique for every instance of the class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Name { get; }
|
string Name { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether to display the UI element or not.
|
/// Whether to display the UI element or not.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Enabled { get; set; } = true;
|
bool Enabled { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -104,7 +104,7 @@ namespace TechbloxModdingAPI
|
||||||
}
|
}
|
||||||
Scheduler.Dispose();
|
Scheduler.Dispose();
|
||||||
var currentAssembly = Assembly.GetExecutingAssembly();
|
var currentAssembly = Assembly.GetExecutingAssembly();
|
||||||
harmony.UnpatchSelf();
|
harmony.UnpatchAll(currentAssembly.GetName().Name);
|
||||||
harmony = null;
|
harmony = null;
|
||||||
Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} shutdown");
|
Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} shutdown");
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,18 +4,17 @@ using RobocraftX.SaveAndLoad;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
|
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using RobocraftX.StateSync;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Persistence
|
namespace TechbloxModdingAPI.Persistence
|
||||||
{
|
{
|
||||||
[HarmonyPatch(typeof(SaveAndLoadCompositionRoot), "ClientComposeTimeStopped")]
|
[HarmonyPatch(typeof(SaveAndLoadCompositionRoot), "Compose")]
|
||||||
class SaveAndLoadCompositionRootPatch
|
class SaveAndLoadCompositionRootPatch
|
||||||
{
|
{
|
||||||
public static EnginesRoot currentEnginesRoot;
|
public static EnginesRoot currentEnginesRoot;
|
||||||
|
|
||||||
public static void Prefix(StateSyncRegistrationHelper stateSyncHelper)
|
public static void Prefix(EnginesRoot enginesRoot)
|
||||||
{
|
{
|
||||||
currentEnginesRoot = stateSyncHelper.enginesRoot;
|
currentEnginesRoot = enginesRoot;
|
||||||
//SerializerManager.RegisterSerializers(enginesRoot);
|
//SerializerManager.RegisterSerializers(enginesRoot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ using RobocraftX.Physics;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Techblox.BuildingDrone;
|
using Techblox.BuildingDrone;
|
||||||
using Techblox.Camera;
|
using Techblox.Camera;
|
||||||
using Techblox.Character;
|
|
||||||
using TechbloxModdingAPI.Blocks;
|
using TechbloxModdingAPI.Blocks;
|
||||||
using TechbloxModdingAPI.Players;
|
using TechbloxModdingAPI.Players;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
|
@ -65,17 +64,14 @@ namespace TechbloxModdingAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the current player belonging to this client. It will be different after entering/leaving simulation.
|
/// Returns the current player belonging to this client.
|
||||||
/// May return null if the local player doesn't exist.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static Player LocalPlayer
|
public static Player LocalPlayer
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var playerId = playerEngine.GetLocalPlayer();
|
if (localPlayer == null || localPlayer.Id != playerEngine.GetLocalPlayer())
|
||||||
if (playerId == uint.MaxValue) return null;
|
localPlayer = new Player(PlayerType.Local);
|
||||||
if (localPlayer == null || localPlayer.Id != playerId)
|
|
||||||
localPlayer = GetInstance(playerId);
|
|
||||||
return localPlayer;
|
return localPlayer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,8 +191,8 @@ namespace TechbloxModdingAPI
|
||||||
/// The player's mass.
|
/// The player's mass.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The mass.</value>
|
/// <value>The mass.</value>
|
||||||
[Obsolete] // We cannot get it clientside or something
|
public float Mass =>
|
||||||
public float Mass => 0;
|
1f / playerEngine.GetCharacterStruct<RigidBodyEntityStruct>(Id).Get().physicsMass.InverseMass;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The player's latest network ping time.
|
/// The player's latest network ping time.
|
||||||
|
@ -214,16 +210,15 @@ namespace TechbloxModdingAPI
|
||||||
/// The player's initial health when entering Simulation (aka Time Running) mode.
|
/// The player's initial health when entering Simulation (aka Time Running) mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The initial health.</value>
|
/// <value>The initial health.</value>
|
||||||
[Obsolete("We can no longer get initial health, returns max health.")]
|
|
||||||
public float InitialHealth
|
public float InitialHealth
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var opt = playerEngine.GetCharacterStruct<CharacterHealthEntityComponent>(Id);
|
var opt = playerEngine.GetCharacterStruct<CharacterHealthEntityStruct>(Id);
|
||||||
return opt ? opt.Get().maxHealth : -1f;
|
return opt ? opt.Get().initialHealth : -1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
set => playerEngine.GetCharacterStruct<CharacterHealthEntityComponent>(Id).Get().maxHealth = value;
|
set => playerEngine.GetCharacterStruct<CharacterHealthEntityStruct>(Id).Get().initialHealth = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -234,25 +229,30 @@ namespace TechbloxModdingAPI
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var opt = playerEngine.GetCharacterStruct<CharacterHealthEntityComponent>(Id);
|
var opt = playerEngine.GetCharacterStruct<CharacterHealthEntityStruct>(Id);
|
||||||
return opt ? opt.Get().currentHealth : -1f;
|
return opt ? opt.Get().currentHealth : -1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
set => playerEngine.GetCharacterStruct<CharacterHealthEntityComponent>(Id).Get().currentHealth = value;
|
set => playerEngine.GetCharacterStruct<CharacterHealthEntityStruct>(Id).Get().currentHealth = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this <see cref="T:TechbloxModdingAPI.Player"/> is damageable.
|
/// Whether this <see cref="T:TechbloxModdingAPI.Player"/> is damageable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value><c>true</c> if damageable; otherwise, <c>false</c>.</value>
|
/// <value><c>true</c> if damageable; otherwise, <c>false</c>.</value>
|
||||||
[Obsolete("Players are probably always damageable")]
|
|
||||||
public bool Damageable
|
public bool Damageable
|
||||||
{
|
{
|
||||||
get => true;
|
get
|
||||||
|
{
|
||||||
|
var opt = playerEngine.GetCharacterStruct<CharacterHealthEntityStruct>(Id);
|
||||||
|
return opt.Get().canTakeDamageStat;
|
||||||
|
}
|
||||||
|
|
||||||
// ReSharper disable once ValueParameterNotUsed
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
ref var healthStruct = ref playerEngine.GetCharacterStruct<CharacterHealthEntityStruct>(Id).Get();
|
||||||
|
healthStruct.canTakeDamage = value;
|
||||||
|
healthStruct.canTakeDamageStat = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,26 +260,30 @@ namespace TechbloxModdingAPI
|
||||||
/// The player's lives when initially entering Simulation (aka Time Running) mode.
|
/// The player's lives when initially entering Simulation (aka Time Running) mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The initial lives.</value>
|
/// <value>The initial lives.</value>
|
||||||
[Obsolete("The player has infinite lives")]
|
|
||||||
public uint InitialLives
|
public uint InitialLives
|
||||||
{
|
{
|
||||||
get => uint.MaxValue;
|
get
|
||||||
|
{
|
||||||
|
var opt = playerEngine.GetCharacterStruct<CharacterLivesEntityComponent>(Id);
|
||||||
|
return opt ? opt.Get().initialLives : uint.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
// ReSharper disable once ValueParameterNotUsed
|
set => playerEngine.GetCharacterStruct<CharacterLivesEntityComponent>(Id).Get().initialLives = value;
|
||||||
set { }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The player's current lives in Simulation (aka Time Running) mode.
|
/// The player's current lives in Simulation (aka Time Running) mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The current lives.</value>
|
/// <value>The current lives.</value>
|
||||||
[Obsolete("The player has infinite lives")]
|
|
||||||
public uint CurrentLives
|
public uint CurrentLives
|
||||||
{
|
{
|
||||||
get => uint.MaxValue;
|
get
|
||||||
|
{
|
||||||
|
var opt = playerEngine.GetCharacterStruct<CharacterLivesEntityComponent>(Id);
|
||||||
|
return opt ? opt.Get().currentLives : uint.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
// ReSharper disable once ValueParameterNotUsed
|
set => playerEngine.GetCharacterStruct<CharacterLivesEntityComponent>(Id).Get().currentLives = value;
|
||||||
set { }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*/// <summary>
|
/*/// <summary>
|
||||||
|
@ -359,18 +363,6 @@ namespace TechbloxModdingAPI
|
||||||
public PlayerBuildingMode BuildingMode => (PlayerBuildingMode)Math.Log((double)playerEngine
|
public PlayerBuildingMode BuildingMode => (PlayerBuildingMode)Math.Log((double)playerEngine
|
||||||
.GetCharacterStruct<TimeStoppedModeComponent>(Id).Get().timeStoppedContext, 2); // It's a bit field in game now
|
.GetCharacterStruct<TimeStoppedModeComponent>(Id).Get().timeStoppedContext, 2); // It's a bit field in game now
|
||||||
|
|
||||||
public PlayerState State =>
|
|
||||||
playerEngine.GetCharacterStruct<CharacterTagEntityStruct>(Id).Get().ID.groupID switch
|
|
||||||
{
|
|
||||||
var group when group == CharacterExclusiveGroups.MachineSpawningGroup => PlayerState.HoldingMachine,
|
|
||||||
var group when group == CharacterExclusiveGroups.OnFootGroup => PlayerState.OnFoot,
|
|
||||||
var group when group == CharacterExclusiveGroups.InPilotSeatGroup => PlayerState.InSeat,
|
|
||||||
var group when group == CharacterExclusiveGroups.DyingOnFootGroup => PlayerState.OnFoot,
|
|
||||||
var group when group == CharacterExclusiveGroups.DyingInPilotSeatGroup => PlayerState.InSeat,
|
|
||||||
var group when group == CharacterExclusiveGroups.DeadGroup => PlayerState.OnFoot,
|
|
||||||
_ => throw new ArgumentOutOfRangeException("", "Unknown player state")
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the player is sprinting.
|
/// Whether the player is sprinting.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -526,15 +518,6 @@ namespace TechbloxModdingAPI
|
||||||
return playerEngine.GetSelectedBlocks(Id);
|
return playerEngine.GetSelectedBlocks(Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the ghost block that shows the block to be placed in build mode.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A block instance or null if not found</returns>
|
|
||||||
public Block GetGhostBlock()
|
|
||||||
{
|
|
||||||
return playerEngine.GetGhostBlock(Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Equals(Player other)
|
public bool Equals(Player other)
|
||||||
{
|
{
|
||||||
if (ReferenceEquals(null, other)) return false;
|
if (ReferenceEquals(null, other)) return false;
|
||||||
|
|
|
@ -8,20 +8,21 @@ using RobocraftX.Common.Input;
|
||||||
using RobocraftX.CR.MachineEditing.BoxSelect;
|
using RobocraftX.CR.MachineEditing.BoxSelect;
|
||||||
using RobocraftX.Physics;
|
using RobocraftX.Physics;
|
||||||
using RobocraftX.Blocks.Ghost;
|
using RobocraftX.Blocks.Ghost;
|
||||||
using RobocraftX.Common;
|
using Gamecraft.GUI.HUDFeedbackBlocks;
|
||||||
|
using RobocraftX.Blocks;
|
||||||
using RobocraftX.Multiplayer;
|
using RobocraftX.Multiplayer;
|
||||||
|
using RobocraftX.PilotSeat;
|
||||||
using RobocraftX.SimulationModeState;
|
using RobocraftX.SimulationModeState;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Techblox.Camera;
|
using Techblox.Camera;
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
using Svelto.ECS.DataStructures;
|
using Svelto.ECS.DataStructures;
|
||||||
|
using Svelto.ECS.EntityStructs;
|
||||||
using Techblox.BuildingDrone;
|
using Techblox.BuildingDrone;
|
||||||
using Techblox.Character;
|
|
||||||
|
|
||||||
using TechbloxModdingAPI.Engines;
|
using TechbloxModdingAPI.Engines;
|
||||||
using TechbloxModdingAPI.Input;
|
using TechbloxModdingAPI.Input;
|
||||||
using TechbloxModdingAPI.Utility;
|
using TechbloxModdingAPI.Utility;
|
||||||
using TechbloxModdingAPI.Utility.ECS;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Players
|
namespace TechbloxModdingAPI.Players
|
||||||
{
|
{
|
||||||
|
@ -50,10 +51,10 @@ namespace TechbloxModdingAPI.Players
|
||||||
public uint GetLocalPlayer()
|
public uint GetLocalPlayer()
|
||||||
{
|
{
|
||||||
if (!isReady) return uint.MaxValue;
|
if (!isReady) return uint.MaxValue;
|
||||||
var (localPlayers, count) = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.LocalPlayers);
|
var localPlayers = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.LocalPlayers).ToBuffer();
|
||||||
if (count > 0)
|
if (localPlayers.count > 0)
|
||||||
{
|
{
|
||||||
return localPlayers[0].ID.entityID;
|
return localPlayers.buffer[0].ID.entityID;
|
||||||
}
|
}
|
||||||
return uint.MaxValue;
|
return uint.MaxValue;
|
||||||
}
|
}
|
||||||
|
@ -61,10 +62,10 @@ namespace TechbloxModdingAPI.Players
|
||||||
public uint GetRemotePlayer()
|
public uint GetRemotePlayer()
|
||||||
{
|
{
|
||||||
if (!isReady) return uint.MaxValue;
|
if (!isReady) return uint.MaxValue;
|
||||||
var (localPlayers, count) = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.RemotePlayers);
|
var localPlayers = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.RemotePlayers).ToBuffer();
|
||||||
if (count > 0)
|
if (localPlayers.count > 0)
|
||||||
{
|
{
|
||||||
return localPlayers[0].ID.entityID;
|
return localPlayers.buffer[0].ID.entityID;
|
||||||
}
|
}
|
||||||
return uint.MaxValue;
|
return uint.MaxValue;
|
||||||
}
|
}
|
||||||
|
@ -113,10 +114,18 @@ namespace TechbloxModdingAPI.Players
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool GetGameOverScreen(uint playerId)
|
||||||
|
{
|
||||||
|
if (entitiesDB == null) return false;
|
||||||
|
ref HudActivatedBlocksEntityStruct habes = ref entitiesDB.QueryEntity<HudActivatedBlocksEntityStruct>(HUDFeedbackBlocksGUIExclusiveGroups.GameOverHudEgid);
|
||||||
|
NativeDynamicArrayCast<EGID> nativeDynamicArrayCast = new NativeDynamicArrayCast<EGID>(habes.activatedBlocksOrdered);
|
||||||
|
return nativeDynamicArrayCast.count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsDead(uint playerId)
|
public bool IsDead(uint playerId)
|
||||||
{
|
{
|
||||||
if (entitiesDB == null) return true;
|
if (entitiesDB == null) return true;
|
||||||
return entitiesDB.Exists<RigidBodyEntityStruct>(playerId, CharacterExclusiveGroups.DeadGroup);
|
return entitiesDB.Exists<RigidBodyEntityStruct>(playerId, CharacterExclusiveGroups.DeadCharacters);
|
||||||
}
|
}
|
||||||
|
|
||||||
// reusable methods
|
// reusable methods
|
||||||
|
@ -165,9 +174,8 @@ namespace TechbloxModdingAPI.Players
|
||||||
var opt = GetCameraStruct<PhysicCameraRayCastEntityStruct>(playerId);
|
var opt = GetCameraStruct<PhysicCameraRayCastEntityStruct>(playerId);
|
||||||
if (!opt) return default;
|
if (!opt) return default;
|
||||||
PhysicCameraRayCastEntityStruct rayCast = opt;
|
PhysicCameraRayCastEntityStruct rayCast = opt;
|
||||||
EGID physicCameraEgid = new EGID(playerId, CameraExclusiveGroups.PhysicCameraGroup);
|
|
||||||
float distance = maxDistance < 0
|
float distance = maxDistance < 0
|
||||||
? GhostBlockUtils.GetBuildInteractionDistance(entitiesDB, rayCast, physicCameraEgid,
|
? GhostBlockUtils.GetBuildInteractionDistance(entitiesDB, rayCast,
|
||||||
GhostBlockUtils.GhostCastMethod.GhostCastProportionalToBlockSize)
|
GhostBlockUtils.GhostCastMethod.GhostCastProportionalToBlockSize)
|
||||||
: maxDistance;
|
: maxDistance;
|
||||||
if (rayCast.hit && rayCast.distance <= distance)
|
if (rayCast.hit && rayCast.distance <= distance)
|
||||||
|
@ -201,9 +209,9 @@ namespace TechbloxModdingAPI.Players
|
||||||
{
|
{
|
||||||
if (!TimeRunningModeUtil.IsTimeRunningMode(entitiesDB))
|
if (!TimeRunningModeUtil.IsTimeRunningMode(entitiesDB))
|
||||||
return;
|
return;
|
||||||
/*PilotSeatGroupUtils.SwapTagTo<OCCUPIED_TAG>(Functions, seatId);
|
PilotSeatGroupUtils.SwapTagTo<OCCUPIED_TAG>(Functions, seatId);
|
||||||
var opt = GetCharacterStruct<CharacterPilotSeatEntityStruct>(playerId, out var group);
|
var opt = GetCharacterStruct<CharacterPilotSeatEntityStruct>(playerId, out var group);
|
||||||
if (!opt) return; - TODO: This is server code and mods run in client code atm. We can only send inputs even in singleplayer as it is.
|
if (!opt) return;
|
||||||
ref CharacterPilotSeatEntityStruct charSeat = ref opt.Get();
|
ref CharacterPilotSeatEntityStruct charSeat = ref opt.Get();
|
||||||
var charId = new EGID(playerId, group);
|
var charId = new EGID(playerId, group);
|
||||||
charSeat.pilotSeatEntity = entitiesDB.GetEntityReference(seatId);
|
charSeat.pilotSeatEntity = entitiesDB.GetEntityReference(seatId);
|
||||||
|
@ -213,18 +221,18 @@ namespace TechbloxModdingAPI.Players
|
||||||
ref var seat = ref entitiesDB.QueryEntity<PilotSeatEntityStruct>(seatId);
|
ref var seat = ref entitiesDB.QueryEntity<PilotSeatEntityStruct>(seatId);
|
||||||
seat.occupyingCharacter = entitiesDB.GetEntityReference(charId);
|
seat.occupyingCharacter = entitiesDB.GetEntityReference(charId);
|
||||||
charSeat.followCam = entitiesDB.QueryEntity<SeatFollowCamComponent>(seatId).followCam;
|
charSeat.followCam = entitiesDB.QueryEntity<SeatFollowCamComponent>(seatId).followCam;
|
||||||
Functions.SwapEntityGroup<CharacterEntityDescriptor>(charId, CharacterExclusiveGroups.InPilotSeatGroup);*/
|
Functions.SwapEntityGroup<CharacterEntityDescriptor>(charId, CharacterExclusiveGroups.InPilotSeatGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ExitSeat(uint playerId)
|
public void ExitSeat(uint playerId)
|
||||||
{
|
{
|
||||||
if (!TimeRunningModeUtil.IsTimeRunningMode(entitiesDB))
|
if (!TimeRunningModeUtil.IsTimeRunningMode(entitiesDB))
|
||||||
return;
|
return;
|
||||||
/*EGID egid = new EGID(playerId, CharacterExclusiveGroups.InPilotSeatGroup);
|
EGID egid = new EGID(playerId, CharacterExclusiveGroups.InPilotSeatGroup);
|
||||||
var opt = entitiesDB.QueryEntityOptional<CharacterPilotSeatEntityStruct>(egid);
|
var opt = entitiesDB.QueryEntityOptional<CharacterPilotSeatEntityStruct>(egid);
|
||||||
if (!opt) return;
|
if (!opt) return;
|
||||||
opt.Get().instantExit = true;
|
opt.Get().instantExit = true;
|
||||||
entitiesDB.PublishEntityChange<CharacterPilotSeatEntityStruct>(egid);*/
|
entitiesDB.PublishEntityChange<CharacterPilotSeatEntityStruct>(egid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SpawnMachine(uint playerId)
|
public bool SpawnMachine(uint playerId)
|
||||||
|
@ -234,11 +242,6 @@ namespace TechbloxModdingAPI.Players
|
||||||
EGID egid = new EGID(playerId, CharacterExclusiveGroups.MachineSpawningGroup);
|
EGID egid = new EGID(playerId, CharacterExclusiveGroups.MachineSpawningGroup);
|
||||||
if (!entitiesDB.Exists<CharacterTagEntityStruct>(egid))
|
if (!entitiesDB.Exists<CharacterTagEntityStruct>(egid))
|
||||||
return false;
|
return false;
|
||||||
if (entitiesDB.QueryEntity<CharacterMachineSpawningValidityComponent>(egid).isMachinePlacementInvalid)
|
|
||||||
{
|
|
||||||
Logging.MetaDebugLog("Machine placement invalid");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
//Functions.SwapEntityGroup<CharacterEntityDescriptor>(egid, CharacterExclusiveGroups.OnFootGroup);
|
//Functions.SwapEntityGroup<CharacterEntityDescriptor>(egid, CharacterExclusiveGroups.OnFootGroup);
|
||||||
FakeInput.ActionInput(playerId, primary: true);
|
FakeInput.ActionInput(playerId, primary: true);
|
||||||
return true;
|
return true;
|
||||||
|
@ -264,11 +267,5 @@ namespace TechbloxModdingAPI.Players
|
||||||
.QueryUniqueEntity<NetworkStatsEntityStruct>(MultiplayerExclusiveGroups.MultiplayerStateGroup)
|
.QueryUniqueEntity<NetworkStatsEntityStruct>(MultiplayerExclusiveGroups.MultiplayerStateGroup)
|
||||||
.networkStats.PingMs;
|
.networkStats.PingMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Block GetGhostBlock(uint playerId)
|
|
||||||
{
|
|
||||||
var egid = new EGID(playerId, GHOST_BLOCKS_ENABLED.Group);
|
|
||||||
return entitiesDB.Exists<DBEntityStruct>(egid) ? Block.New(egid) : null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using RobocraftX.Character;
|
using RobocraftX.Character;
|
||||||
using RobocraftX.Character.Movement;
|
using RobocraftX.Character.Movement;
|
||||||
using RobocraftX.Common.Input;
|
using RobocraftX.Common.Input;
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
namespace TechbloxModdingAPI.Players
|
|
||||||
{
|
|
||||||
public enum PlayerState
|
|
||||||
{
|
|
||||||
HoldingMachine,
|
|
||||||
OnFoot,
|
|
||||||
InSeat
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -29,7 +29,7 @@ namespace TechbloxModdingAPI.Players
|
||||||
[APITestCase(TestType.EditMode)]
|
[APITestCase(TestType.EditMode)]
|
||||||
public static void PositionTest()
|
public static void PositionTest()
|
||||||
{
|
{
|
||||||
Player p = Player.LocalPlayer;
|
Player p = new Player(PlayerType.Local);
|
||||||
if (!Assert.Errorless(() => { p.Teleport(0, 0, 0, relative: false); }, "Player.Teleport(origin) errored: ", "Player teleported to origin successfully.")) return;
|
if (!Assert.Errorless(() => { p.Teleport(0, 0, 0, relative: false); }, "Player.Teleport(origin) errored: ", "Player teleported to origin successfully.")) return;
|
||||||
if (!Assert.CloseTo(p.Position, float3.zero, "Player is not close to origin despite being teleported there.", "Player.Position is at origin.")) return;
|
if (!Assert.CloseTo(p.Position, float3.zero, "Player is not close to origin despite being teleported there.", "Player.Position is at origin.")) return;
|
||||||
if (!Assert.Errorless(() => { p.Position = float3.zero + 1; }, "Player.Position = origin+1 errored: ", "Player moved to origin+1.")) return;
|
if (!Assert.Errorless(() => { p.Position = float3.zero + 1; }, "Player.Position = origin+1 errored: ", "Player moved to origin+1.")) return;
|
||||||
|
@ -39,14 +39,15 @@ namespace TechbloxModdingAPI.Players
|
||||||
[APITestCase(TestType.Game)]
|
[APITestCase(TestType.Game)]
|
||||||
public static void SeatEventTestBuild()
|
public static void SeatEventTestBuild()
|
||||||
{
|
{
|
||||||
Block.PlaceNew(BlockIDs.DriverSeat, Player.LocalPlayer.Position);
|
Player.LocalPlayer.SeatEntered += Assert.CallsBack<PlayerSeatEventArgs>("SeatEntered");
|
||||||
|
Player.LocalPlayer.SeatExited += Assert.CallsBack<PlayerSeatEventArgs>("SeatExited");
|
||||||
|
Block.PlaceNew(BlockIDs.DriverSeat, -1f);
|
||||||
}
|
}
|
||||||
|
|
||||||
[APITestCase(TestType.SimulationMode)]
|
[APITestCase(TestType.SimulationMode)]
|
||||||
public static IEnumerator<TaskContract> SeatEventTestSim()
|
public static IEnumerator<TaskContract> SeatEventTestSim()
|
||||||
{
|
{
|
||||||
Player.LocalPlayer.SeatEntered += Assert.CallsBack<PlayerSeatEventArgs>("SeatEntered");
|
yield return new WaitForSecondsEnumerator(1).Continue();
|
||||||
Player.LocalPlayer.SeatExited += Assert.CallsBack<PlayerSeatEventArgs>("SeatExited");
|
|
||||||
Assert.Equal(Player.LocalPlayer.SpawnMachine(), true, "Failed to spawn the player's machine.", "Successfully spawned the player's machine.");
|
Assert.Equal(Player.LocalPlayer.SpawnMachine(), true, "Failed to spawn the player's machine.", "Successfully spawned the player's machine.");
|
||||||
yield return new WaitForSecondsEnumerator(1).Continue();
|
yield return new WaitForSecondsEnumerator(1).Continue();
|
||||||
var seats = Game.CurrentGame().GetBlocksInGame(BlockIDs.DriverSeat);
|
var seats = Game.CurrentGame().GetBlocksInGame(BlockIDs.DriverSeat);
|
||||||
|
@ -55,7 +56,7 @@ namespace TechbloxModdingAPI.Players
|
||||||
{
|
{
|
||||||
Logging.MetaLog("Waiting for a seat to be spawned...");
|
Logging.MetaLog("Waiting for a seat to be spawned...");
|
||||||
yield return new WaitForSecondsEnumerator(1).Continue();
|
yield return new WaitForSecondsEnumerator(1).Continue();
|
||||||
Logging.MetaLog("Spawn machine: " + Player.LocalPlayer.SpawnMachine());
|
Console.WriteLine("Spawn machine: " + Player.LocalPlayer.SpawnMachine());
|
||||||
seats = Game.CurrentGame().GetBlocksInGame(BlockIDs.DriverSeat);
|
seats = Game.CurrentGame().GetBlocksInGame(BlockIDs.DriverSeat);
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
|
@ -67,21 +68,11 @@ namespace TechbloxModdingAPI.Players
|
||||||
}
|
}
|
||||||
|
|
||||||
if (seats[0] is Seat seat)
|
if (seats[0] is Seat seat)
|
||||||
{
|
|
||||||
Assert.Errorless(() => Player.LocalPlayer.EnterSeat(seat), "Failed to enter seat.",
|
Assert.Errorless(() => Player.LocalPlayer.EnterSeat(seat), "Failed to enter seat.",
|
||||||
"Entered seat successfully.");
|
"Entered seat successfully.");
|
||||||
while (Player.LocalPlayer.State != PlayerState.InSeat)
|
|
||||||
{
|
|
||||||
bool cont = false;
|
|
||||||
Client.Instance.PromptUser(new SingleChoicePrompt("Testing", $"Enter the seat at {seat.Position} pls", "OK", () => cont = true));
|
|
||||||
while (!cont)
|
|
||||||
yield return Yield.It;
|
|
||||||
yield return new WaitForSecondsEnumerator(5f).Continue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
Assert.Fail("Found a seat that is not a seat!");
|
Assert.Fail("Found a seat that is not a seat!");
|
||||||
yield return new WaitForSecondsEnumerator(5).Continue();
|
yield return new WaitForSecondsEnumerator(1).Continue();
|
||||||
Assert.Errorless(() => Player.LocalPlayer.ExitSeat(), "Failed to exit seat.",
|
Assert.Errorless(() => Player.LocalPlayer.ExitSeat(), "Failed to exit seat.",
|
||||||
"Exited seat successfully.");
|
"Exited seat successfully.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ using UnityEngine;
|
||||||
using Gamecraft.Damage;
|
using Gamecraft.Damage;
|
||||||
using RobocraftX.Common;
|
using RobocraftX.Common;
|
||||||
using RobocraftX.Physics;
|
using RobocraftX.Physics;
|
||||||
using Techblox.TimeRunning.Clusters;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI
|
namespace TechbloxModdingAPI
|
||||||
{
|
{
|
||||||
|
@ -21,7 +20,7 @@ namespace TechbloxModdingAPI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Cluster Cluster => cluster ??= clusterId == uint.MaxValue // Return cluster or if it's null then set it
|
public Cluster Cluster => cluster ??= clusterId == uint.MaxValue // Return cluster or if it's null then set it
|
||||||
? Block.BlockEngine.GetCluster(Id.entityID) // If we don't have a clusterId set then get it from the game
|
? Block.BlockEngine.GetCluster(Id.entityID) // If we don't have a clusterId set then get it from the game
|
||||||
: GetInstance(new EGID(clusterId, ClustersExclusiveGroups.SIMULATION_CLUSTERS_GROUP),
|
: GetInstance(new EGID(clusterId, CommonExclusiveGroups.SIMULATION_CLUSTERS_GROUP),
|
||||||
egid => new Cluster(egid)); // Otherwise get the cluster from the ID
|
egid => new Cluster(egid)); // Otherwise get the cluster from the ID
|
||||||
|
|
||||||
private Cluster cluster;
|
private Cluster cluster;
|
||||||
|
@ -74,16 +73,15 @@ namespace TechbloxModdingAPI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete] //Cannot get mass even from UECS
|
|
||||||
public float Mass
|
public float Mass
|
||||||
{
|
{
|
||||||
get => 0f;
|
get => math.rcp(GetStruct().physicsMass.InverseMass);
|
||||||
//set => GetStruct().physicsMass.InverseMass = math.rcp(value);
|
//set => GetStruct().physicsMass.InverseMass = math.rcp(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float3 CenterOfMass
|
public float3 CenterOfMass
|
||||||
{
|
{
|
||||||
get => 0f; //TODO
|
get => GetStruct().physicsMass.CenterOfMass;
|
||||||
//set => GetStruct().physicsMass.CenterOfMass = value;
|
//set => GetStruct().physicsMass.CenterOfMass = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,20 +92,20 @@ namespace TechbloxModdingAPI
|
||||||
|
|
||||||
public float InitialHealth
|
public float InitialHealth
|
||||||
{
|
{
|
||||||
get => 0f;
|
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).initialHealth;
|
||||||
set { }
|
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).initialHealth = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float CurrentHealth
|
public float CurrentHealth
|
||||||
{
|
{
|
||||||
get => 0f;
|
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).currentHealth;
|
||||||
set { }
|
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).currentHealth = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float HealthMultiplier
|
public float HealthMultiplier
|
||||||
{
|
{
|
||||||
get => 0f;
|
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).healthMultiplier;
|
||||||
set { }
|
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).healthMultiplier = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using RobocraftX.Schedulers;
|
|
||||||
using Svelto.Tasks;
|
using Svelto.Tasks;
|
||||||
using Svelto.Tasks.ExtraLean;
|
using Svelto.Tasks.ExtraLean;
|
||||||
using Svelto.Tasks.Unity.Internal;
|
using Svelto.Tasks.Unity.Internal;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Tasks
|
namespace TechbloxModdingAPI.Tasks
|
||||||
{
|
{
|
||||||
public class OnGuiRunner : SteppableRunner<ExtraLeanSveltoTask<IEnumerator>>
|
public class OnGuiRunner : BaseRunner<ExtraLeanSveltoTask<IEnumerator>>
|
||||||
{
|
{
|
||||||
public OnGuiRunner(string name, uint runningOrder = 0)
|
public OnGuiRunner(string name, uint runningOrder = 0)
|
||||||
: base(name)
|
: base(name)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,84 +1,382 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using BepInEx;
|
|
||||||
using BepInEx.Bootstrap;
|
|
||||||
using HarmonyLib;
|
|
||||||
using RobocraftX.FrontEnd;
|
|
||||||
using TechbloxModdingAPI.App;
|
using TechbloxModdingAPI.App;
|
||||||
|
using HarmonyLib;
|
||||||
|
using IllusionInjector;
|
||||||
|
// test
|
||||||
|
using RobocraftX.FrontEnd;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
using UnityEngine;
|
||||||
|
using Svelto.Tasks;
|
||||||
|
using Svelto.Tasks.Lean;
|
||||||
|
using TechbloxModdingAPI.Blocks;
|
||||||
using TechbloxModdingAPI.Commands;
|
using TechbloxModdingAPI.Commands;
|
||||||
|
using TechbloxModdingAPI.Players;
|
||||||
|
using TechbloxModdingAPI.Tasks;
|
||||||
|
using TechbloxModdingAPI.Utility;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Tests
|
namespace TechbloxModdingAPI.Tests
|
||||||
{
|
{
|
||||||
#if DEBUG // The API should be loaded by other plugins, but it can be used by itself for testing
|
#if DEBUG
|
||||||
[BepInPlugin("org.exmods.TechbloxModdingAPIPluginTest", PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
|
// unused by design
|
||||||
[BepInProcess("Techblox.exe")]
|
/// <summary>
|
||||||
public class TechbloxModdingAPIPluginTest : BaseUnityPlugin
|
/// Modding API implemented as a standalone IPA Plugin.
|
||||||
|
/// Ideally, TechbloxModdingAPI should be loaded by another mod; not itself
|
||||||
|
/// </summary>
|
||||||
|
class TechbloxModdingAPIPluginTest : IllusionPlugin.IEnhancedPlugin
|
||||||
{
|
{
|
||||||
private void Awake()
|
|
||||||
{
|
|
||||||
Main.Init();
|
|
||||||
Client.EnterMenu += (sender, args) => throw new Exception("Test handler always throws an exception!");
|
|
||||||
Client.EnterMenu += (sender, args) => Console.WriteLine("EnterMenu handler after erroring handler");
|
|
||||||
Game.Enter += (s, a) =>
|
|
||||||
{
|
|
||||||
Player.LocalPlayer.SeatEntered += (sender, args) =>
|
|
||||||
Console.WriteLine($"Player {Player.LocalPlayer} entered seat {args.Seat}");
|
|
||||||
Player.LocalPlayer.SeatExited += (sender, args) =>
|
|
||||||
Console.WriteLine($"Player {Player.LocalPlayer} exited seat {args.Seat}");
|
|
||||||
};
|
|
||||||
|
|
||||||
CommandBuilder.Builder()
|
private static Harmony harmony { get; set; }
|
||||||
.Name("Exit")
|
|
||||||
.Description("Close Techblox immediately, without any prompts")
|
|
||||||
.Action(() => { UnityEngine.Application.Quit(); })
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
CommandBuilder.Builder()
|
public override string Name { get; } = Assembly.GetExecutingAssembly().GetName().Name;
|
||||||
.Name("SetFOV")
|
|
||||||
.Description("Set the player camera's field of view")
|
|
||||||
.Action((float d) => { UnityEngine.Camera.main.fieldOfView = d; })
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
Game.AddPersistentDebugInfo("InstalledMods", InstalledMods);
|
public override string Version { get; } = Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||||
|
|
||||||
// Plugin startup logic
|
public string HarmonyID { get; } = "org.git.exmods.modtainers.techbloxmoddingapi";
|
||||||
Logger.LogInfo($"Plugin {PluginInfo.PLUGIN_GUID} is loaded!");
|
|
||||||
|
|
||||||
#if TEST
|
public override void OnApplicationQuit()
|
||||||
TestRoot.RunTests();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
{
|
||||||
Main.Shutdown();
|
Main.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string modsString;
|
public override void OnApplicationStart()
|
||||||
|
{
|
||||||
|
FileLog.Reset();
|
||||||
|
Harmony.DEBUG = true;
|
||||||
|
Main.Init();
|
||||||
|
Logging.MetaDebugLog($"Version group id {ApiExclusiveGroups.versionGroup}");
|
||||||
|
// 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
|
||||||
|
Client.EnterMenu += (sender, args) => throw new Exception("Test handler always throws an exception!");
|
||||||
|
Client.EnterMenu += (sender, args) => Console.WriteLine("EnterMenu handler after erroring handler");
|
||||||
|
Game.Enter += (s, a) =>
|
||||||
|
{
|
||||||
|
Player.LocalPlayer.SeatEntered += (sender, args) =>
|
||||||
|
Console.WriteLine($"Player {Player.LocalPlayer} entered seat {args.Seat}");
|
||||||
|
Player.LocalPlayer.SeatExited += (sender, args) =>
|
||||||
|
Console.WriteLine($"Player {Player.LocalPlayer} exited seat {args.Seat}");
|
||||||
|
};
|
||||||
|
|
||||||
|
// debug/test commands
|
||||||
|
if (Dependency.Hell("ExtraCommands"))
|
||||||
|
{
|
||||||
|
CommandBuilder.Builder()
|
||||||
|
.Name("Exit")
|
||||||
|
.Description("Close Techblox 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
|
||||||
|
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.Cube, new float3(x, y, z), force: true);
|
||||||
|
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.Cube, new float3(x + i, y, z + j));
|
||||||
|
sw.Stop();
|
||||||
|
Logging.CommandLog("Finished in " + sw.ElapsedMilliseconds + "ms");
|
||||||
|
})
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
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 = color;
|
||||||
|
Logging.CommandLog("Colored block to " + color);
|
||||||
|
|
||||||
|
}).Build();
|
||||||
|
|
||||||
|
CommandBuilder.Builder("MoveBlockByID", "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();
|
||||||
|
|
||||||
|
CommandBuilder.Builder("TestChunkHealth", "Sets the chunk looked at to the given health.")
|
||||||
|
.Action((float val, float max) =>
|
||||||
|
{
|
||||||
|
var body = new Player(PlayerType.Local).GetSimBodyLookedAt();
|
||||||
|
if (body == null) return;
|
||||||
|
body.CurrentHealth = val;
|
||||||
|
body.InitialHealth = max;
|
||||||
|
Logging.CommandLog("Health set to: " + val);
|
||||||
|
}).Build();
|
||||||
|
|
||||||
|
CommandBuilder.Builder("placeBlockGroup", "Places some blocks in a group")
|
||||||
|
.Action((float x, float y, float z) =>
|
||||||
|
{
|
||||||
|
var pos = new float3(x, y, z);
|
||||||
|
var group = BlockGroup.Create(new Block(BlockIDs.Cube, pos) {Color = BlockColors.Aqua});
|
||||||
|
new Block(BlockIDs.Cube, pos += new float3(1, 0, 0))
|
||||||
|
{Color = BlockColors.Blue, BlockGroup = group};
|
||||||
|
new Block(BlockIDs.Cube, pos += new float3(1, 0, 0))
|
||||||
|
{Color = BlockColors.Green, BlockGroup = group};
|
||||||
|
new Block(BlockIDs.Cube, pos + new float3(1, 0, 0))
|
||||||
|
{Color = BlockColors.Lime, BlockGroup = group};
|
||||||
|
}).Build();
|
||||||
|
|
||||||
|
CommandBuilder.Builder("placeCustomBlock", "Places a custom block, needs a custom catalog and assets.")
|
||||||
|
.Action((float x, float y, float z) =>
|
||||||
|
{
|
||||||
|
Logging.CommandLog("Block placed: " +
|
||||||
|
Block.PlaceNew((BlockIDs) 500, new float3(0, 0, 0)));
|
||||||
|
}).Build();
|
||||||
|
|
||||||
|
CommandBuilder.Builder("toggleTimeMode", "Enters or exits simulation.")
|
||||||
|
.Action((float x, float y, float z) =>
|
||||||
|
{
|
||||||
|
Game.CurrentGame().ToggleTimeMode();
|
||||||
|
}).Build();
|
||||||
|
|
||||||
|
CommandBuilder.Builder("testColorBlock", "Tests coloring a block to default color")
|
||||||
|
.Action(() => Player.LocalPlayer.GetBlockLookedAt().Color = BlockColors.Default).Build();
|
||||||
|
CommandBuilder.Builder("testMaterialBlock", "Tests materialing a block to default material")
|
||||||
|
.Action(() => Player.LocalPlayer.GetBlockLookedAt().Material = BlockMaterial.Default).Build();
|
||||||
|
CommandBuilder.Builder("testGameName", "Tests changing the game name")
|
||||||
|
.Action(() => Game.CurrentGame().Name = "Test").Build();
|
||||||
|
CommandBuilder.Builder("makeBlockStatic", "Makes a block you look at static")
|
||||||
|
.Action(() => Player.LocalPlayer.GetBlockLookedAt().Static = true).Build();
|
||||||
|
|
||||||
|
Game.AddPersistentDebugInfo("InstalledMods", InstalledMods);
|
||||||
|
/*Block.Placed += (sender, args) =>
|
||||||
|
Logging.MetaDebugLog("Placed block " + args.Block);
|
||||||
|
Block.Removed += (sender, args) =>
|
||||||
|
Logging.MetaDebugLog("Removed block " + args.Block);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// dependency test
|
||||||
|
if (Dependency.Hell("TechbloxScripting", new Version("0.0.1.0")))
|
||||||
|
{
|
||||||
|
Logging.LogWarning("You're in TechbloxScripting dependency hell");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Log("Compatible TechbloxScripting detected");
|
||||||
|
}
|
||||||
|
// Interface test
|
||||||
|
/*Group uiGroup = new Group(new Rect(20, 20, 200, 500), "TechbloxModdingAPI_UITestGroup", true);
|
||||||
|
var button = new Button("TEST");
|
||||||
|
button.OnClick += (b, __) => { Logging.MetaDebugLog($"Click on {((Interface.IMGUI.Button)b).Name}");};
|
||||||
|
var button2 = new Button("TEST2");
|
||||||
|
button2.OnClick += (b, __) => { Logging.MetaDebugLog($"Click on {((Interface.IMGUI.Button)b).Name}");};
|
||||||
|
Text uiText = new Text("<Input!>", multiline: true);
|
||||||
|
uiText.OnEdit += (t, txt) => { Logging.MetaDebugLog($"Text in {((Text)t).Name} is now '{txt}'"); };
|
||||||
|
Label uiLabel = new Label("Label!");
|
||||||
|
Image uiImg = new Image(name:"Behold this texture!");
|
||||||
|
uiImg.Enabled = false;
|
||||||
|
uiGroup.AddElement(button);
|
||||||
|
uiGroup.AddElement(button2);
|
||||||
|
uiGroup.AddElement(uiText);
|
||||||
|
uiGroup.AddElement(uiLabel);
|
||||||
|
uiGroup.AddElement(uiImg);*/
|
||||||
|
|
||||||
|
/*Addressables.LoadAssetAsync<Texture2D>("Assets/Art/Textures/UI/FrontEndMap/RCX_Blue_Background_5k.jpg")
|
||||||
|
.Completed +=
|
||||||
|
handle =>
|
||||||
|
{
|
||||||
|
uiImg.Texture = handle.Result;
|
||||||
|
uiImg.Enabled = true;
|
||||||
|
Logging.MetaDebugLog($"Got blue bg asset {handle.Result}");
|
||||||
|
};*/
|
||||||
|
|
||||||
|
/*((FasterList<GuiInputMap.GuiInputMapElement>)AccessTools.Property(typeof(GuiInputMap), "GuiInputsButtonDown").GetValue(null))
|
||||||
|
.Add(new GuiInputMap.GuiInputMapElement(RewiredConsts.Action.ToggleCommandLine, GuiIn))*/
|
||||||
|
|
||||||
|
/*Game.Enter += (sender, e) =>
|
||||||
|
{
|
||||||
|
ushort lastKey = ushort.MaxValue;
|
||||||
|
foreach (var kv in FullGameFields._dataDb.GetValues<CubeListData>()
|
||||||
|
.OrderBy(kv=>ushort.Parse(kv.Key)))
|
||||||
|
{
|
||||||
|
var data = (CubeListData) kv.Value;
|
||||||
|
ushort currentKey = ushort.Parse(kv.Key);
|
||||||
|
var toReplace = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{"Scalable", ""}, {"Qtr", "Quarter"}, {"RNeg", "Rounded Negative"},
|
||||||
|
{"Neg", "Negative"}, {"Tetra", "Tetrahedron"},
|
||||||
|
{"RWedge", "Rounded Wedge"}, {"RTetra", "Rounded Tetrahedron"}
|
||||||
|
};
|
||||||
|
string name = LocalizationService.Localize(data.CubeNameKey).Split(' ').Select(str =>
|
||||||
|
str.Length > 0 ? char.ToUpper(str[0]) + str.Substring(1) : str).Aggregate((a, b) => a + b)
|
||||||
|
.Replace("-", "");
|
||||||
|
foreach (var rkv in toReplace)
|
||||||
|
{
|
||||||
|
name = Regex.Replace(name, rkv.Key + "([A-Z]|$)", rkv.Value + "$1");
|
||||||
|
}
|
||||||
|
Console.WriteLine($"{name}{(currentKey != lastKey + 1 ? $" = {currentKey}" : "")},");
|
||||||
|
lastKey = currentKey;
|
||||||
|
}
|
||||||
|
};*/
|
||||||
|
/*Game.Enter += (sender, e) =>
|
||||||
|
{
|
||||||
|
ushort lastKey = ushort.MaxValue;
|
||||||
|
Console.WriteLine("Materials:\n" + FullGameFields._dataDb.GetValues<MaterialPropertiesData>()
|
||||||
|
.OrderBy(kv => ushort.Parse(kv.Key))
|
||||||
|
.Select(kv =>
|
||||||
|
{
|
||||||
|
ushort currentKey = ushort.Parse(kv.Key);
|
||||||
|
string result = $"{((MaterialPropertiesData)kv.Value).Name}{(currentKey != lastKey + 1 ? $" = {kv.Key}" : "")},";
|
||||||
|
lastKey = currentKey;
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
.Aggregate((a, b) => a + "\n" + b));
|
||||||
|
};*/
|
||||||
|
|
||||||
|
CommandBuilder.Builder("takeScreenshot", "Enables the screenshot taker")
|
||||||
|
.Action(() =>
|
||||||
|
{
|
||||||
|
Game.CurrentGame().EnableScreenshotTaker();
|
||||||
|
}).Build();
|
||||||
|
|
||||||
|
CommandBuilder.Builder("testPositionDefault", "Tests the Block.Position property's default value.")
|
||||||
|
.Action(() =>
|
||||||
|
{
|
||||||
|
IEnumerator<TaskContract> Loop()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
Console.WriteLine("A");
|
||||||
|
var block = Block.PlaceNew(BlockIDs.Cube, 1);
|
||||||
|
Console.WriteLine("B");
|
||||||
|
while (!block.Exists)
|
||||||
|
yield return Yield.It;
|
||||||
|
Console.WriteLine("C");
|
||||||
|
block.Remove();
|
||||||
|
Console.WriteLine("D");
|
||||||
|
while (block.Exists)
|
||||||
|
yield return Yield.It;
|
||||||
|
Console.WriteLine("E - Pos: " + block.Position);
|
||||||
|
block.Position = 4;
|
||||||
|
Console.WriteLine("F - Pos: " + block.Position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loop().RunOn(Scheduler.leanRunner);
|
||||||
|
}).Build();
|
||||||
|
|
||||||
|
CommandBuilder.Builder("importAssetBundle")
|
||||||
|
.Action(() =>
|
||||||
|
{
|
||||||
|
Logging.CommandLog("Importing asset bundle...");
|
||||||
|
var ab = AssetBundle.LoadFromFile(
|
||||||
|
@"filepath");
|
||||||
|
Logging.CommandLog("Imported asset bundle: " + ab);
|
||||||
|
var assets = ab.LoadAllAssets();
|
||||||
|
Logging.CommandLog("Loaded " + assets.Length + " assets");
|
||||||
|
foreach (var asset in assets)
|
||||||
|
{
|
||||||
|
Logging.CommandLog(asset);
|
||||||
|
}
|
||||||
|
}).Build();
|
||||||
|
Client.EnterMenu += (sender, args) => Scheduler.Schedule(new Once(() => Client.Instance.CloseBetaPopup()));
|
||||||
|
|
||||||
|
Game.Enter += (sender, args) =>
|
||||||
|
Console.WriteLine(
|
||||||
|
$"Current game selection data: {FullGameFields._gameSelectionData.gameMode} - {FullGameFields._gameSelectionData.saveType}");
|
||||||
|
#if TEST
|
||||||
|
TestRoot.RunTests();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private string modsString;
|
||||||
private string InstalledMods()
|
private string InstalledMods()
|
||||||
{
|
{
|
||||||
if (modsString != null) return modsString;
|
if (modsString != null) return modsString;
|
||||||
StringBuilder sb = new StringBuilder("Installed mods:");
|
StringBuilder sb = new StringBuilder("Installed mods:");
|
||||||
foreach (var (_, plugin) in Chainloader.PluginInfos)
|
foreach (var plugin in PluginManager.Plugins)
|
||||||
sb.Append("\n" + plugin.Metadata.Name + " - " + plugin.Metadata.Version);
|
sb.Append("\n" + plugin.Name + " - " + plugin.Version);
|
||||||
return modsString = sb.ToString();
|
return modsString = sb.ToString();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch]
|
|
||||||
public class MinimumSpecsPatch
|
|
||||||
{
|
|
||||||
public static bool Prefix(ref bool __result)
|
|
||||||
{
|
|
||||||
__result = true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodInfo TargetMethod()
|
[HarmonyPatch]
|
||||||
|
public class MinimumSpecsPatch
|
||||||
{
|
{
|
||||||
return ((Func<bool>) MinimumSpecsCheck.CheckRequirementsMet).Method;
|
public static bool Prefix(ref bool __result)
|
||||||
|
{
|
||||||
|
__result = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodInfo TargetMethod()
|
||||||
|
{
|
||||||
|
return ((Func<bool>) MinimumSpecsCheck.CheckRequirementsMet).Method;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,12 +200,11 @@ namespace TechbloxModdingAPI.Tests
|
||||||
cont = false;
|
cont = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cont)
|
yield return Yield.It;
|
||||||
yield return enumerator.Current;
|
|
||||||
} while (cont);
|
} while (cont);
|
||||||
}
|
}
|
||||||
|
|
||||||
yield return new WaitForSecondsEnumerator(1f).Continue();
|
yield return Yield.It;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using BepInEx.Bootstrap;
|
|
||||||
|
using IllusionInjector;
|
||||||
|
using IllusionPlugin;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Utility
|
namespace TechbloxModdingAPI.Utility
|
||||||
{
|
{
|
||||||
|
@ -13,11 +15,11 @@ namespace TechbloxModdingAPI.Utility
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The plugin.</returns>
|
/// <returns>The plugin.</returns>
|
||||||
/// <param name="name">The plugin's name.</param>
|
/// <param name="name">The plugin's name.</param>
|
||||||
public static BepInEx.PluginInfo GetPlugin(string name)
|
public static IPlugin GetPlugin(string name)
|
||||||
{
|
{
|
||||||
foreach(var plugin in Chainloader.PluginInfos.Values)
|
foreach(IPlugin plugin in PluginManager.Plugins)
|
||||||
{
|
{
|
||||||
if (plugin.Metadata.Name == name)
|
if (plugin.Name == name)
|
||||||
{
|
{
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
@ -33,15 +35,45 @@ namespace TechbloxModdingAPI.Utility
|
||||||
/// <param name="name">The plugin's name.</param>
|
/// <param name="name">The plugin's name.</param>
|
||||||
public static Version GetPluginVersion(string name)
|
public static Version GetPluginVersion(string name)
|
||||||
{
|
{
|
||||||
var plugin = GetPlugin(name);
|
IPlugin plugin = GetPlugin(name);
|
||||||
if (plugin != null) {
|
if (plugin != null) {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return plugin.Metadata.Version;
|
return new Version(plugin.Version);
|
||||||
} catch (Exception e) when (e is ArgumentException or FormatException or OverflowException) {}
|
} 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 plugin.GetType().Assembly.GetName().Version;
|
||||||
}
|
}
|
||||||
return null;
|
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,56 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using HarmonyLib;
|
|
||||||
using Svelto.DataStructures;
|
|
||||||
using Svelto.ECS;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Utility.ECS
|
|
||||||
{
|
|
||||||
public static partial class NativeApiExtensions
|
|
||||||
{
|
|
||||||
[SuppressMessage("ReSharper", "StaticMemberInGenericType")]
|
|
||||||
private static class EntitiesDBHelper<T> where T : unmanaged, IEntityComponent
|
|
||||||
{ // Each type gets a new set of fields here (that's what the ReSharper warning is about too)
|
|
||||||
public static readonly Lazy<MethodInfo> EntityStream =
|
|
||||||
new(() => AccessTools.PropertyGetter(typeof(EntitiesDB), "_entityStream"));
|
|
||||||
|
|
||||||
public static readonly Lazy<FieldInfo> Streams = new(() =>
|
|
||||||
AccessTools.Field(EntityStream.Value.ReturnType, "_streams"));
|
|
||||||
|
|
||||||
public static readonly Lazy<FieldInfo> Consumers = new(() =>
|
|
||||||
AccessTools.Field(typeof(EntityStream<T>), "_consumers"));
|
|
||||||
|
|
||||||
public static readonly Lazy<MethodInfo> TryGetValue =
|
|
||||||
new(AccessTools.Method(Streams.Value.FieldType, "TryGetValue"));
|
|
||||||
|
|
||||||
public static readonly Lazy<FieldInfo> RingBuffer =
|
|
||||||
new(() => AccessTools.Field(typeof(Consumer<T>), "_ringBuffer"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static EntityStream<T> GetEntityStream<T>(this EntitiesDB entitiesDB) where T : unmanaged, IEntityComponent
|
|
||||||
{
|
|
||||||
// EntitiesStreams (internal)
|
|
||||||
var entitiesStreams = EntitiesDBHelper<T>.EntityStream.Value.Invoke(entitiesDB, Array.Empty<object>());
|
|
||||||
// FasterDictionary<RefWrapperType, ITypeSafeStream> (interface is internal)
|
|
||||||
var streams = EntitiesDBHelper<T>.Streams.Value.GetValue(entitiesStreams);
|
|
||||||
|
|
||||||
var parameters = new object[] { TypeRefWrapper<T>.wrapper, null };
|
|
||||||
var success = EntitiesDBHelper<T>.TryGetValue.Value.Invoke(streams, parameters);
|
|
||||||
if (!(bool)success)
|
|
||||||
return null; // There is no entity stream for this type
|
|
||||||
return (EntityStream<T>)parameters[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ThreadSafeFasterList<Consumer<T>> GetConsumers<T>(this EntityStream<T> stream) where T : unmanaged, IEntityComponent
|
|
||||||
{
|
|
||||||
return (ThreadSafeFasterList<Consumer<T>>)EntitiesDBHelper<T>.Consumers.Value.GetValue(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static RingBuffer<(T, EGID)> GetRingBuffer<T>(this Consumer<T> consumer) where T : unmanaged, IEntityComponent
|
|
||||||
{
|
|
||||||
return (RingBuffer<(T, EGID)>)EntitiesDBHelper<T>.RingBuffer.Value.GetValue(consumer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -122,11 +122,11 @@ namespace TechbloxModdingAPI.Utility
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ECSMainGameResourceManagers _managers
|
public static ECSResourceManagers _managers
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return (ECSMainGameResourceManagers)fgcr?.Field("_gameManagers").GetValue();
|
return (ECSResourceManagers)fgcr?.Field("_managers").GetValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.ECS.Hybrid;
|
using Svelto.ECS.Hybrid;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Utility.ECS
|
namespace TechbloxModdingAPI.Utility
|
||||||
{
|
{
|
||||||
public static class ManagedApiExtensions
|
public static class ManagedApiExtensions
|
||||||
{
|
{
|
||||||
|
@ -29,8 +29,7 @@ namespace TechbloxModdingAPI.Utility.ECS
|
||||||
/// <param name="group">The group of the entity if the object can have multiple</param>
|
/// <param name="group">The group of the entity if the object can have multiple</param>
|
||||||
/// <typeparam name="T">The component to query</typeparam>
|
/// <typeparam name="T">The component to query</typeparam>
|
||||||
/// <returns>A reference to the component or a dummy value</returns>
|
/// <returns>A reference to the component or a dummy value</returns>
|
||||||
public static OptionalRef<T> QueryEntityOptional<T>(this EntitiesDB entitiesDB, EcsObjectBase obj,
|
public static OptionalRef<T> QueryEntityOptional<T>(this EntitiesDB entitiesDB, EcsObjectBase obj, ExclusiveGroupStruct group = default)
|
||||||
ExclusiveGroupStruct group = default)
|
|
||||||
where T : struct, IEntityViewComponent
|
where T : struct, IEntityViewComponent
|
||||||
{
|
{
|
||||||
EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group);
|
EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group);
|
||||||
|
@ -46,30 +45,14 @@ namespace TechbloxModdingAPI.Utility.ECS
|
||||||
/// <param name="group">The group of the entity if the object can have multiple</param>
|
/// <param name="group">The group of the entity if the object can have multiple</param>
|
||||||
/// <typeparam name="T">The component to query</typeparam>
|
/// <typeparam name="T">The component to query</typeparam>
|
||||||
/// <returns>A reference to the component or a dummy value</returns>
|
/// <returns>A reference to the component or a dummy value</returns>
|
||||||
public static ref T QueryEntityOrDefault<T>(this EntitiesDB entitiesDB, EcsObjectBase obj,
|
public static ref T QueryEntityOrDefault<T>(this EntitiesDB entitiesDB, EcsObjectBase obj, ExclusiveGroupStruct group = default)
|
||||||
ExclusiveGroupStruct group = default)
|
|
||||||
where T : struct, IEntityViewComponent
|
where T : struct, IEntityViewComponent
|
||||||
{
|
{
|
||||||
EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group);
|
EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group);
|
||||||
var opt = QueryEntityOptional<T>(entitiesDB, id);
|
var opt = QueryEntityOptional<T>(entitiesDB, id);
|
||||||
if (opt) return ref opt.Get();
|
if (opt) return ref opt.Get();
|
||||||
if (obj.InitData.Valid) return ref obj.InitData.Initializer(id).GetOrAdd<T>();
|
if (obj.InitData.Valid) return ref obj.InitData.Initializer(id).GetOrCreate<T>();
|
||||||
return ref opt.Get(); //Default value
|
return ref opt.Get(); //Default value
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Query entities as OptionalRefs. The elements always exist, it's just a nice way to encapsulate the data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="entitiesDB"></param>
|
|
||||||
/// <param name="group"></param>
|
|
||||||
/// <param name="select"></param>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <typeparam name="TR"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static RefCollection<T> QueryEntitiesOptional<T>(this EntitiesDB entitiesDB, ExclusiveGroupStruct group) where T : struct, IEntityViewComponent
|
|
||||||
{
|
|
||||||
var (buffer, ids, count) = entitiesDB.QueryEntities<T>(group);
|
|
||||||
return new RefCollection<T>(count, buffer, ids, group);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,14 +1,8 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Svelto.DataStructures;
|
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using Svelto.Tasks;
|
|
||||||
using Svelto.Tasks.Lean;
|
|
||||||
using TechbloxModdingAPI.Tasks;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Utility.ECS
|
namespace TechbloxModdingAPI.Utility
|
||||||
{
|
{
|
||||||
public static partial class NativeApiExtensions
|
public static class NativeApiExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to query an entity and returns an optional that contains the result if succeeded.
|
/// Attempts to query an entity and returns an optional that contains the result if succeeded.
|
||||||
|
@ -34,8 +28,7 @@ namespace TechbloxModdingAPI.Utility.ECS
|
||||||
/// <param name="group">The group of the entity if the object can have multiple</param>
|
/// <param name="group">The group of the entity if the object can have multiple</param>
|
||||||
/// <typeparam name="T">The component to query</typeparam>
|
/// <typeparam name="T">The component to query</typeparam>
|
||||||
/// <returns>A reference to the component or a dummy value</returns>
|
/// <returns>A reference to the component or a dummy value</returns>
|
||||||
public static OptionalRef<T> QueryEntityOptional<T>(this EntitiesDB entitiesDB, EcsObjectBase obj,
|
public static OptionalRef<T> QueryEntityOptional<T>(this EntitiesDB entitiesDB, EcsObjectBase obj, ExclusiveGroupStruct group = default)
|
||||||
ExclusiveGroupStruct group = default)
|
|
||||||
where T : unmanaged, IEntityComponent
|
where T : unmanaged, IEntityComponent
|
||||||
{
|
{
|
||||||
EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group);
|
EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group);
|
||||||
|
@ -51,14 +44,13 @@ namespace TechbloxModdingAPI.Utility.ECS
|
||||||
/// <param name="group">The group of the entity if the object can have multiple</param>
|
/// <param name="group">The group of the entity if the object can have multiple</param>
|
||||||
/// <typeparam name="T">The component to query</typeparam>
|
/// <typeparam name="T">The component to query</typeparam>
|
||||||
/// <returns>A reference to the component or a dummy value</returns>
|
/// <returns>A reference to the component or a dummy value</returns>
|
||||||
public static ref T QueryEntityOrDefault<T>(this EntitiesDB entitiesDB, EcsObjectBase obj,
|
public static ref T QueryEntityOrDefault<T>(this EntitiesDB entitiesDB, EcsObjectBase obj, ExclusiveGroupStruct group = default)
|
||||||
ExclusiveGroupStruct group = default)
|
|
||||||
where T : unmanaged, IEntityComponent
|
where T : unmanaged, IEntityComponent
|
||||||
{
|
{
|
||||||
EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group);
|
EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group);
|
||||||
var opt = QueryEntityOptional<T>(entitiesDB, id);
|
var opt = QueryEntityOptional<T>(entitiesDB, id);
|
||||||
if (opt) return ref opt.Get();
|
if (opt) return ref opt.Get();
|
||||||
if (obj.InitData.Valid) return ref obj.InitData.Initializer(id).GetOrAdd<T>();
|
if (obj.InitData.Valid) return ref obj.InitData.Initializer(id).GetOrCreate<T>();
|
||||||
/*if (!obj.InitData.Valid) return ref opt.Get(); //Default value
|
/*if (!obj.InitData.Valid) return ref opt.Get(); //Default value
|
||||||
var init = obj.InitData.Initializer(id);
|
var init = obj.InitData.Initializer(id);
|
||||||
// Do not create the component if missing, as that can trigger Add() listeners that, in some cases, may be
|
// Do not create the component if missing, as that can trigger Add() listeners that, in some cases, may be
|
||||||
|
@ -66,64 +58,5 @@ namespace TechbloxModdingAPI.Utility.ECS
|
||||||
if (init.Has<T>()) return ref init.Get<T>();*/
|
if (init.Has<T>()) return ref init.Get<T>();*/
|
||||||
return ref opt.Get(); //Default value
|
return ref opt.Get(); //Default value
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Publishes an entity change, ignoring duplicate publishes and delaying changes as necessary.
|
|
||||||
/// It will only publish in the next frame.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="entitiesDB">The entities DB to publish to</param>
|
|
||||||
/// <param name="id">The ECS object that got changed</param>
|
|
||||||
/// <typeparam name="T">The component that changed</typeparam>
|
|
||||||
public static void PublishEntityChangeDelayed<T>(this EntitiesDB entitiesDB, EGID id)
|
|
||||||
where T : unmanaged, IEntityComponent
|
|
||||||
{
|
|
||||||
PublishChanges<T>(entitiesDB, id).RunOn(Scheduler.leanRunner);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerator<TaskContract> PublishChanges<T>(EntitiesDB entitiesDB, EGID id)
|
|
||||||
where T : unmanaged, IEntityComponent
|
|
||||||
{
|
|
||||||
yield return Yield.It;
|
|
||||||
var entityStream = entitiesDB.GetEntityStream<T>();
|
|
||||||
if (entityStream is null)
|
|
||||||
yield break; // There is no entity stream for this type
|
|
||||||
var consumers = entityStream.GetConsumers();
|
|
||||||
if (consumers == null)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Consumers is null");
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool waitForConsumers;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
waitForConsumers = false;
|
|
||||||
for (int i = 0; i < consumers.count; i++)
|
|
||||||
{
|
|
||||||
var buffer = consumers[i].GetRingBuffer();
|
|
||||||
if (buffer.Count + 1 <= buffer.Capacity) continue;
|
|
||||||
waitForConsumers = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waitForConsumers) yield return Yield.It;
|
|
||||||
} while (waitForConsumers);
|
|
||||||
entitiesDB.PublishEntityChange<T>(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Query entities as OptionalRefs. The elements always exist, it's just a nice way to encapsulate the data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="entitiesDB"></param>
|
|
||||||
/// <param name="group"></param>
|
|
||||||
/// <param name="select"></param>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <typeparam name="TR"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static RefCollection<T> QueryEntitiesOptional<T>(this EntitiesDB entitiesDB, ExclusiveGroupStruct group) where T : unmanaged, IEntityComponent
|
|
||||||
{
|
|
||||||
var (buffer, ids, count) = entitiesDB.QueryEntities<T>(group);
|
|
||||||
return new RefCollection<T>(count, buffer, ids, group);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,9 +4,8 @@ using Svelto.ECS;
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Utility
|
namespace TechbloxModdingAPI.Utility
|
||||||
{
|
{
|
||||||
public ref struct OptionalRef<T> where T : struct, IBaseEntityComponent
|
public ref struct OptionalRef<T> where T : struct, IEntityComponent
|
||||||
{
|
{
|
||||||
private readonly EGID entityId;
|
|
||||||
private readonly State state;
|
private readonly State state;
|
||||||
private readonly uint index;
|
private readonly uint index;
|
||||||
private NB<T> array;
|
private NB<T> array;
|
||||||
|
@ -14,22 +13,19 @@ namespace TechbloxModdingAPI.Utility
|
||||||
private readonly EntityInitializer initializer;
|
private readonly EntityInitializer initializer;
|
||||||
//The possible fields are: (index && (array || managedArray)) || initializer
|
//The possible fields are: (index && (array || managedArray)) || initializer
|
||||||
|
|
||||||
public OptionalRef(NB<T> array, uint index, EGID entityId = default)
|
public OptionalRef(NB<T> array, uint index)
|
||||||
{
|
{
|
||||||
state = State.Native;
|
state = State.Native;
|
||||||
this.array = array;
|
this.array = array;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.entityId = entityId;
|
|
||||||
initializer = default;
|
initializer = default;
|
||||||
managedArray = default;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public OptionalRef(MB<T> array, uint index, EGID entityId = default)
|
public OptionalRef(MB<T> array, uint index)
|
||||||
{
|
{
|
||||||
state = State.Managed;
|
state = State.Managed;
|
||||||
managedArray = array;
|
managedArray = array;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.entityId = entityId;
|
|
||||||
initializer = default;
|
initializer = default;
|
||||||
this.array = default;
|
this.array = default;
|
||||||
}
|
}
|
||||||
|
@ -39,9 +35,8 @@ namespace TechbloxModdingAPI.Utility
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">The object with the initializer</param>
|
/// <param name="obj">The object with the initializer</param>
|
||||||
/// <param name="unmanaged">Whether the struct is unmanaged</param>
|
/// <param name="unmanaged">Whether the struct is unmanaged</param>
|
||||||
public OptionalRef(EcsObjectBase obj, bool unmanaged, EGID entityId = default)
|
public OptionalRef(EcsObjectBase obj, bool unmanaged)
|
||||||
{
|
{
|
||||||
this.entityId = entityId;
|
|
||||||
if (obj.InitData.Valid)
|
if (obj.InitData.Valid)
|
||||||
{
|
{
|
||||||
initializer = obj.InitData.Initializer(obj.Id);
|
initializer = obj.InitData.Initializer(obj.Id);
|
||||||
|
@ -54,7 +49,6 @@ namespace TechbloxModdingAPI.Utility
|
||||||
}
|
}
|
||||||
array = default;
|
array = default;
|
||||||
index = default;
|
index = default;
|
||||||
managedArray = default;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -65,25 +59,11 @@ namespace TechbloxModdingAPI.Utility
|
||||||
{
|
{
|
||||||
CompRefCache.Default = default; //The default value can be changed by mods
|
CompRefCache.Default = default; //The default value can be changed by mods
|
||||||
if (state == State.Empty) return ref CompRefCache.Default;
|
if (state == State.Empty) return ref CompRefCache.Default;
|
||||||
if ((state & State.Initializer) != State.Empty) return ref initializer.GetOrAdd<T>();
|
if ((state & State.Initializer) != State.Empty) return ref initializer.GetOrCreate<T>();
|
||||||
if ((state & State.Native) != State.Empty) return ref array[index];
|
if ((state & State.Native) != State.Empty) return ref array[index];
|
||||||
return ref managedArray[index];
|
return ref managedArray[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A non-by-ref view that allows getting and setting the value.
|
|
||||||
/// </summary>
|
|
||||||
public T Value
|
|
||||||
{
|
|
||||||
get => Get();
|
|
||||||
set => Get() = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The ID of the entity this component belongs to or default if it doesn't exist.
|
|
||||||
/// </summary>
|
|
||||||
public EGID EGID => entityId;
|
|
||||||
|
|
||||||
public bool Exists => state != State.Empty;
|
public bool Exists => state != State.Empty;
|
||||||
public T? Nullable() => this ? Get() : default;
|
public T? Nullable() => this ? Get() : default;
|
||||||
|
|
||||||
|
@ -91,8 +71,6 @@ namespace TechbloxModdingAPI.Utility
|
||||||
|
|
||||||
public static implicit operator bool(OptionalRef<T> opt) => opt.state != State.Empty;
|
public static implicit operator bool(OptionalRef<T> opt) => opt.state != State.Empty;
|
||||||
|
|
||||||
public static implicit operator EGID(OptionalRef<T> opt) => opt.entityId;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an instance of a struct T that can be referenced.
|
/// Creates an instance of a struct T that can be referenced.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
using System;
|
|
||||||
using Svelto.DataStructures;
|
|
||||||
using Svelto.ECS;
|
|
||||||
using Svelto.ECS.Hybrid;
|
|
||||||
using Svelto.ECS.Internal;
|
|
||||||
|
|
||||||
namespace TechbloxModdingAPI.Utility
|
|
||||||
{
|
|
||||||
public readonly ref struct RefCollection<T> where T : struct, IBaseEntityComponent
|
|
||||||
{
|
|
||||||
private readonly bool managed;
|
|
||||||
private readonly int count;
|
|
||||||
private readonly NB<T> nativeArray;
|
|
||||||
private readonly MB<T> managedArray;
|
|
||||||
private readonly NativeEntityIDs nativeIDs;
|
|
||||||
private readonly ManagedEntityIDs managedIDs;
|
|
||||||
private readonly ExclusiveGroupStruct group;
|
|
||||||
|
|
||||||
public RefCollection(int count, MB<T> managedArray, ManagedEntityIDs managedIDs, ExclusiveGroupStruct group)
|
|
||||||
{
|
|
||||||
this.count = count;
|
|
||||||
this.managedArray = managedArray;
|
|
||||||
this.managedIDs = managedIDs;
|
|
||||||
this.group = group;
|
|
||||||
managed = true;
|
|
||||||
nativeArray = default;
|
|
||||||
nativeIDs = default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RefCollection(int count, NB<T> nativeArray, NativeEntityIDs nativeIDs, ExclusiveGroupStruct group)
|
|
||||||
{
|
|
||||||
this.count = count;
|
|
||||||
this.nativeArray = nativeArray;
|
|
||||||
this.nativeIDs = nativeIDs;
|
|
||||||
this.group = group;
|
|
||||||
managed = false;
|
|
||||||
managedArray = default;
|
|
||||||
managedIDs = default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Enumerator GetEnumerator() => new(this);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The amount of items in the collection.
|
|
||||||
/// </summary>
|
|
||||||
public int Count => count;
|
|
||||||
|
|
||||||
public T[] ToArray() => ToArray(a => a.Component);
|
|
||||||
|
|
||||||
public TA[] ToArray<TA>(Func<(T Component, EGID ID), TA> transformFunction, Predicate<(T Component, EGID ID)> predicateFunction = null)
|
|
||||||
{
|
|
||||||
var result = new TA[Count];
|
|
||||||
int i = 0;
|
|
||||||
foreach (var opt in this)
|
|
||||||
{
|
|
||||||
if (predicateFunction != null && !predicateFunction((opt.Get(), opt.EGID))) continue;
|
|
||||||
result[i] = transformFunction((opt.Get(), opt.EGID));
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref struct Enumerator
|
|
||||||
{
|
|
||||||
private RefCollection<T> coll;
|
|
||||||
private int index;
|
|
||||||
|
|
||||||
public Enumerator(RefCollection<T> collection)
|
|
||||||
{
|
|
||||||
index = -1;
|
|
||||||
coll = collection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OptionalRef<T> Current
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (coll.count <= index && index >= 0) return default;
|
|
||||||
if (coll.managed)
|
|
||||||
return new OptionalRef<T>(coll.managedArray, (uint)index,
|
|
||||||
new EGID(coll.managedIDs[index], coll.group));
|
|
||||||
return new OptionalRef<T>(coll.nativeArray, (uint)index,
|
|
||||||
new EGID(coll.nativeIDs[index], coll.group));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool MoveNext()
|
|
||||||
{
|
|
||||||
return ++index < coll.count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@ namespace TechbloxModdingAPI.Utility
|
||||||
{
|
{
|
||||||
public class WeakDictionary<TKey, TValue> : IDictionary<TKey, TValue> where TValue : class
|
public class WeakDictionary<TKey, TValue> : IDictionary<TKey, TValue> where TValue : class
|
||||||
{
|
{
|
||||||
private readonly Dictionary<TKey, WeakReference<TValue>> _dictionary = new();
|
private Dictionary<TKey, WeakReference<TValue>> _dictionary = new Dictionary<TKey, WeakReference<TValue>>();
|
||||||
|
|
||||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||||
{
|
{
|
||||||
|
@ -19,26 +19,58 @@ namespace TechbloxModdingAPI.Utility
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
public void Add(KeyValuePair<TKey, TValue> item) => Add(item.Key, item.Value);
|
{
|
||||||
public void Clear() => _dictionary.Clear();
|
return GetEnumerator();
|
||||||
public bool Contains(KeyValuePair<TKey, TValue> item) =>
|
}
|
||||||
TryGetValue(item.Key, out var value) && item.Value == value;
|
|
||||||
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) =>
|
public void Add(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
Add(item.Key, item.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_dictionary.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
return TryGetValue(item.Key, out var value) && item.Value == value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||||
|
{
|
||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
public bool Remove(KeyValuePair<TKey, TValue> item) => Contains(item) && Remove(item.Key);
|
}
|
||||||
|
|
||||||
|
public bool Remove(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
return Contains(item) && Remove(item.Key);
|
||||||
|
}
|
||||||
|
|
||||||
public int Count => _dictionary.Count;
|
public int Count => _dictionary.Count;
|
||||||
public bool IsReadOnly => false;
|
public bool IsReadOnly => false;
|
||||||
public bool ContainsKey(TKey key) => TryGetValue(key, out _);
|
|
||||||
public void Add(TKey key, TValue value) => _dictionary.Add(key, new WeakReference<TValue>(value));
|
public bool ContainsKey(TKey key)
|
||||||
public bool Remove(TKey key) => _dictionary.Remove(key);
|
{
|
||||||
|
return _dictionary.ContainsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(TKey key, TValue value)
|
||||||
|
{
|
||||||
|
_dictionary.Add(key, new WeakReference<TValue>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(TKey key)
|
||||||
|
{
|
||||||
|
return _dictionary.Remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
public bool TryGetValue(TKey key, out TValue value)
|
public bool TryGetValue(TKey key, out TValue value)
|
||||||
{
|
{
|
||||||
value = null;
|
value = null;
|
||||||
bool ret = _dictionary.TryGetValue(key, out var reference) && reference.TryGetTarget(out value);
|
return _dictionary.TryGetValue(key, out var reference) && reference.TryGetTarget(out value);
|
||||||
if (!ret) _dictionary.Remove(key);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TValue this[TKey key]
|
public TValue this[TKey key]
|
||||||
|
@ -49,37 +81,12 @@ namespace TechbloxModdingAPI.Utility
|
||||||
set => _dictionary[key] = new WeakReference<TValue>(value);
|
set => _dictionary[key] = new WeakReference<TValue>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ICollection<TKey> Keys => new KeyCollection(this);
|
public ICollection<TKey> Keys => _dictionary.Keys;
|
||||||
public ICollection<TValue> Values => new ValueCollection(this);
|
public ICollection<TValue> Values => new ValueCollection(this);
|
||||||
|
|
||||||
public class KeyCollection : ICollection<TKey>, IReadOnlyCollection<TKey>
|
|
||||||
{
|
|
||||||
private readonly WeakDictionary<TKey, TValue> _dictionary;
|
|
||||||
internal KeyCollection(WeakDictionary<TKey, TValue> dictionary)
|
|
||||||
{
|
|
||||||
_dictionary = dictionary;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<TKey> GetEnumerator()
|
|
||||||
{
|
|
||||||
using var enumerator = _dictionary.GetEnumerator();
|
|
||||||
while (enumerator.MoveNext())
|
|
||||||
yield return enumerator.Current.Key;
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
public void Add(TKey item) => throw new NotSupportedException("The key collection is read only.");
|
|
||||||
public void Clear() => throw new NotSupportedException("The key collection is read only.");
|
|
||||||
public bool Contains(TKey item) => _dictionary.ContainsKey(item);
|
|
||||||
public void CopyTo(TKey[] array, int arrayIndex) => throw new NotImplementedException();
|
|
||||||
public bool Remove(TKey item) => throw new NotSupportedException("The key collection is read only.");
|
|
||||||
public int Count => _dictionary.Count;
|
|
||||||
public bool IsReadOnly => true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ValueCollection : ICollection<TValue>, IReadOnlyCollection<TValue>
|
public class ValueCollection : ICollection<TValue>, IReadOnlyCollection<TValue>
|
||||||
{
|
{
|
||||||
private readonly WeakDictionary<TKey, TValue> _dictionary;
|
private WeakDictionary<TKey, TValue> _dictionary;
|
||||||
internal ValueCollection(WeakDictionary<TKey, TValue> dictionary)
|
internal ValueCollection(WeakDictionary<TKey, TValue> dictionary)
|
||||||
{
|
{
|
||||||
_dictionary = dictionary;
|
_dictionary = dictionary;
|
||||||
|
@ -89,15 +96,41 @@ namespace TechbloxModdingAPI.Utility
|
||||||
{
|
{
|
||||||
using var enumerator = _dictionary.GetEnumerator();
|
using var enumerator = _dictionary.GetEnumerator();
|
||||||
while (enumerator.MoveNext())
|
while (enumerator.MoveNext())
|
||||||
|
{
|
||||||
yield return enumerator.Current.Value;
|
yield return enumerator.Current.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(TValue item)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("The value collection is read only.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("The value collection is read only.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(TValue item)
|
||||||
|
{
|
||||||
|
return _dictionary.Any(kv => kv.Value == item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(TValue[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(TValue item)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("The value collection is read only.");
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
public void Add(TValue item) => throw new NotSupportedException("The value collection is read only.");
|
|
||||||
public void Clear() => throw new NotSupportedException("The value collection is read only.");
|
|
||||||
public bool Contains(TValue item) => _dictionary.Any(kv => kv.Value == item);
|
|
||||||
public void CopyTo(TValue[] array, int arrayIndex) => throw new NotImplementedException();
|
|
||||||
public bool Remove(TValue item) => throw new NotSupportedException("The value collection is read only.");
|
|
||||||
public int Count => _dictionary.Count;
|
public int Count => _dictionary.Count;
|
||||||
public bool IsReadOnly => true;
|
public bool IsReadOnly => true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ PROJECT_NAME = "TechbloxModdingAPI"
|
||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = "v2.2.0"
|
PROJECT_NUMBER = "v2.0.0"
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
|
|
Loading…
Reference in a new issue