Compare commits
64 commits
Author | SHA1 | Date | |
---|---|---|---|
5dff88d703 | |||
a8a451f8e4 | |||
67f32b8810 | |||
b3b1e9b9e7 | |||
e0cd7f6aec | |||
23439abde3 | |||
5e90c5ee26 | |||
5117b69500 | |||
f70b65e796 | |||
55344d1352 | |||
dfe1bfb504 | |||
a610623644 | |||
f9aa6ce2bb | |||
23abe47c72 | |||
c0ef8f1fae | |||
c4a9125ed3 | |||
3eecdf2cf5 | |||
2db7b607f0 | |||
7f63944a6e | |||
c6dae688fe | |||
7b2ac973d8 | |||
0ec47cd38b | |||
ddaa933e7d | |||
5fea7dc3b3 | |||
4684b33c69 | |||
d27bcee8d5 | |||
09d3c5e81c | |||
966fdd4c3a | |||
5602ef9268 | |||
93a0b2287a | |||
4ac8d53a2d | |||
f817becc6e | |||
2a1782cd82 | |||
fef66c349d | |||
4580ae3b66 | |||
f1376f5df6 | |||
2179ba6386 | |||
1a986056a1 | |||
|
d891f12701 | ||
|
1cb663b4d1 | ||
0bd348bd47 | |||
3929144171 | |||
92965404ce | |||
58cfba443e | |||
ee6a0e3af6 | |||
|
9e6edc19bd | ||
d581ec598a | |||
1e9d1c8f81 | |||
53bdd27166 | |||
2172364d26 | |||
|
50ebf4f0a6 | ||
|
167ea5388b | ||
47126d2d79 | |||
c5e9599c46 | |||
3f2139d592 | |||
|
9e47bbcd9a | ||
|
cda57afade | ||
|
4a9ceecc29 | ||
16521ab7eb | |||
cc4ed3e174 | |||
|
e0aa052305 | ||
d842df7681 | |||
3592c6f464 | |||
5bbb54c0c5 |
83 changed files with 5483 additions and 2714 deletions
|
@ -5,7 +5,7 @@ from pathlib import Path, PurePath
|
|||
import re
|
||||
import os
|
||||
|
||||
DLL_EXCLUSIONS_REGEX = r"(System|Microsoft|Mono|IronPython|DiscordRPC)\."
|
||||
DLL_EXCLUSIONS_REGEX = r"(System|Microsoft|Mono|IronPython|DiscordRPC|IllusionInjector|IllusionPlugin|netstandard)\."
|
||||
|
||||
def getAssemblyReferences(path):
|
||||
asmDir = Path(path)
|
||||
|
@ -15,10 +15,12 @@ def getAssemblyReferences(path):
|
|||
addedPath = "../"
|
||||
asmDir = Path(addedPath + path)
|
||||
for child in asmDir.iterdir():
|
||||
if child.is_file() and re.search(DLL_EXCLUSIONS_REGEX, str(child), re.I) is None and str(child).lower().endswith(".dll"):
|
||||
if child.is_file() and re.search(DLL_EXCLUSIONS_REGEX, str(child)) is None and str(child).lower().endswith(".dll"):
|
||||
childstr = str(child)
|
||||
childstr = os.path.relpath(childstr, addedPath).replace("\\", "/")
|
||||
result.append(childstr)
|
||||
result.sort(key=str.lower)
|
||||
result = [path + "/IllusionInjector.dll", path + "/IllusionPlugin.dll"] + result # Always put it on top
|
||||
return result
|
||||
|
||||
def buildReferencesXml(path):
|
||||
|
@ -39,7 +41,7 @@ if __name__ == "__main__":
|
|||
args = parser.parse_args()
|
||||
|
||||
print("Building Assembly references")
|
||||
asmXml = buildReferencesXml("../ref/Techblox_Data/Managed")
|
||||
asmXml = buildReferencesXml("../ref_TB/Techblox_Data/Managed")
|
||||
# print(asmXml)
|
||||
|
||||
with open("../TechbloxModdingAPI/TechbloxModdingAPI.csproj", "r") as xmlFile:
|
||||
|
@ -51,7 +53,7 @@ if __name__ == "__main__":
|
|||
if depsStart is None or depsEnd is None:
|
||||
print("Unable to find dependency XML comments, aborting!")
|
||||
exit(1)
|
||||
newFileStr = fileStr[:depsStart.start()] + "\n" + asmXml + "\n" + fileStr[depsEnd.end() + 1:]
|
||||
newFileStr = fileStr[:depsStart.start() - 1] + "\n" + asmXml + "\n" + fileStr[depsEnd.end() + 1:]
|
||||
with open("../TechbloxModdingAPI/TechbloxModdingAPI.csproj", "w") as xmlFile:
|
||||
print("Writing Assembly references")
|
||||
xmlFile.write(newFileStr)
|
||||
|
|
10
CodeGenerator/App.config
Normal file
10
CodeGenerator/App.config
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="mscorlib" publicKeyToken="b77a5c561934e089" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
|
@ -8,7 +8,6 @@ using System.Reflection;
|
|||
using Gamecraft.Tweaks;
|
||||
using RobocraftX.Common;
|
||||
using Svelto.ECS;
|
||||
using Techblox.EngineBlock;
|
||||
|
||||
namespace CodeGenerator
|
||||
{
|
||||
|
@ -23,7 +22,7 @@ namespace CodeGenerator
|
|||
group = GetGroup(name) + "_BLOCK_BUILD_GROUP";
|
||||
}
|
||||
|
||||
if (!group.Contains("."))
|
||||
if (!group.Contains('.'))
|
||||
group = "CommonExclusiveGroups." + group;
|
||||
|
||||
var codeUnit = new CodeCompileUnit();
|
||||
|
@ -68,7 +67,7 @@ namespace CodeGenerator
|
|||
codeUnit.Namespaces.Add(ns);
|
||||
|
||||
var provider = CodeDomProvider.CreateProvider("CSharp");
|
||||
var path = $@"..\..\..\TechbloxModdingAPI\Blocks\{name}.cs";
|
||||
var path = $@"../../../../TechbloxModdingAPI/Blocks/{name}.cs";
|
||||
using (var sw = new StreamWriter(path))
|
||||
{
|
||||
provider.GenerateCodeFromCompileUnit(codeUnit, sw, new CodeGeneratorOptions {BracingStyle = "C"});
|
||||
|
@ -97,6 +96,8 @@ namespace CodeGenerator
|
|||
{
|
||||
if (!typeof(IEntityComponent).IsAssignableFrom(type))
|
||||
throw new ArgumentException("Type must be an entity component");
|
||||
bool reflection = type.IsNotPublic;
|
||||
var reflectedType = new CodeSnippetExpression($"HarmonyLib.AccessTools.TypeByName(\"{type.FullName}\")");
|
||||
foreach (var field in type.GetFields())
|
||||
{
|
||||
var attr = field.GetCustomAttribute<TweakableStatAttribute>();
|
||||
|
@ -108,10 +109,20 @@ namespace CodeGenerator
|
|||
}
|
||||
|
||||
propName = char.ToUpper(propName[0]) + propName.Substring(1);
|
||||
var structFieldReference = new CodeFieldReferenceExpression(new CodeMethodInvokeExpression(
|
||||
var getStruct = new CodeMethodInvokeExpression(
|
||||
new CodeMethodReferenceExpression(new CodeSnippetExpression("BlockEngine"),
|
||||
"GetBlockInfo", new CodeTypeReference(type)),
|
||||
new CodeThisReferenceExpression());
|
||||
CodeExpression structFieldReference = new CodeFieldReferenceExpression(getStruct, field.Name);
|
||||
CodeExpression reflectedGet = new CodeCastExpression(field.FieldType, new CodeMethodInvokeExpression(
|
||||
new CodeMethodReferenceExpression(new CodeSnippetExpression("BlockEngine"),
|
||||
"GetBlockInfo", new CodeTypeReference(type)),
|
||||
new CodeThisReferenceExpression()), field.Name);
|
||||
"GetBlockInfo"),
|
||||
new CodeThisReferenceExpression(), reflectedType, new CodePrimitiveExpression(field.Name)));
|
||||
CodeExpression reflectedSet = new CodeMethodInvokeExpression(
|
||||
new CodeMethodReferenceExpression(new CodeSnippetExpression("BlockEngine"),
|
||||
"SetBlockInfo"),
|
||||
new CodeThisReferenceExpression(), reflectedType, new CodePrimitiveExpression(field.Name),
|
||||
new CodePropertySetValueReferenceExpression());
|
||||
cl.Members.Add(new CodeMemberProperty
|
||||
{
|
||||
Name = propName,
|
||||
|
@ -119,18 +130,23 @@ namespace CodeGenerator
|
|||
HasSet = true,
|
||||
GetStatements =
|
||||
{
|
||||
new CodeMethodReturnStatement(structFieldReference)
|
||||
new CodeMethodReturnStatement(reflection ? reflectedGet : structFieldReference)
|
||||
},
|
||||
SetStatements =
|
||||
{
|
||||
new CodeAssignStatement(structFieldReference, new CodePropertySetValueReferenceExpression())
|
||||
reflection
|
||||
? (CodeStatement)new CodeExpressionStatement(reflectedSet)
|
||||
: new CodeAssignStatement(structFieldReference, new CodePropertySetValueReferenceExpression())
|
||||
},
|
||||
Type = new CodeTypeReference(field.FieldType),
|
||||
Attributes = MemberAttributes.Public | MemberAttributes.Final,
|
||||
Comments =
|
||||
{
|
||||
_start, new CodeCommentStatement($"Gets or sets the {baseClass}'s {propName} property." +
|
||||
$" {(attr != null ? "Tweakable stat." : "May not be saved.")}", true), _end
|
||||
_start,
|
||||
new CodeCommentStatement($"Gets or sets the {baseClass}'s {propName} property." +
|
||||
$" {(attr != null ? "Tweakable stat." : "May not be saved.")}",
|
||||
true),
|
||||
_end
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,12 @@
|
|||
using System.Collections.Generic;
|
||||
using HarmonyLib;
|
||||
using RobocraftX.Blocks;
|
||||
using RobocraftX.Common;
|
||||
using RobocraftX.GroupTags;
|
||||
using RobocraftX.PilotSeat;
|
||||
using Svelto.ECS;
|
||||
using Techblox.EngineBlock;
|
||||
using Techblox.ServoBlocksServer;
|
||||
using Techblox.WheelRigBlock;
|
||||
|
||||
namespace CodeGenerator
|
||||
|
@ -9,12 +14,17 @@ namespace CodeGenerator
|
|||
internal class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
GenerateBlockClasses();
|
||||
}
|
||||
|
||||
private static void GenerateBlockClasses()
|
||||
{
|
||||
var bcg = new BlockClassGenerator();
|
||||
bcg.Generate("Engine", null, new Dictionary<string, string>
|
||||
{
|
||||
{ "engineOn", "On" }
|
||||
}, typeof(EngineBlockComponent), // Simulation time properties
|
||||
}, AccessTools.TypeByName("Techblox.EngineBlock.EngineBlockComponent"), // Simulation time properties
|
||||
typeof(EngineBlockTweakableComponent), typeof(EngineBlockReadonlyComponent));
|
||||
bcg.Generate("DampedSpring", "DAMPEDSPRING_BLOCK_GROUP", new Dictionary<string, string>
|
||||
{
|
||||
|
@ -22,7 +32,7 @@ namespace CodeGenerator
|
|||
},
|
||||
typeof(TweakableJointDampingComponent), typeof(DampedSpringReadOnlyStruct));
|
||||
bcg.Generate("LogicGate", "LOGIC_BLOCK_GROUP");
|
||||
bcg.Generate("Servo", types: typeof(ServoReadOnlyStruct), renames: new Dictionary<string, string>
|
||||
bcg.Generate("Servo", types: typeof(ServoReadOnlyTweakableComponent), renames: new Dictionary<string, string>
|
||||
{
|
||||
{"minDeviation", "MinimumAngle"},
|
||||
{"maxDeviation", "MaximumAngle"},
|
||||
|
@ -37,6 +47,7 @@ namespace CodeGenerator
|
|||
{"pistonVelocity", "MaximumForce"}
|
||||
}, typeof(PistonReadOnlyStruct));
|
||||
bcg.Generate("Motor", null, null, typeof(MotorReadOnlyStruct));
|
||||
//bcg.Generate("ObjectID", "ObjectIDBlockExclusiveGroups.OBJECT_ID_BLOCK_GROUP", null, typeof(ObjectIDTweakableComponent));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
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")]
|
4
CodeGenerator/packages.config
Normal file
4
CodeGenerator/packages.config
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Lib.Harmony" version="2.2.0" targetFramework="net472" />
|
||||
</packages>
|
1574
MakeEverythingPublicInGame/MakeEverythingPublicInGame.csproj
Normal file
1574
MakeEverythingPublicInGame/MakeEverythingPublicInGame.csproj
Normal file
File diff suppressed because it is too large
Load diff
25
MakeEverythingPublicInGame/Program.cs
Normal file
25
MakeEverythingPublicInGame/Program.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using System.Text.RegularExpressions;
|
||||
using Mono.Cecil;
|
||||
|
||||
Console.WriteLine("Starting assembly editing...");
|
||||
var fileRegex =
|
||||
new Regex(".*(Techblox|Gamecraft|RobocraftX|FullGame|RobocraftECS|DataLoader|RCX|GameState|Svelto\\.ECS)[^/]*(\\.dll)");
|
||||
foreach (var file in Directory.EnumerateFiles(@"../../../../../ref/Techblox_Data/Managed"))
|
||||
{
|
||||
if (!fileRegex.IsMatch(file)) continue;
|
||||
Console.WriteLine(file);
|
||||
ProcessAssembly(file);
|
||||
}
|
||||
|
||||
void ProcessAssembly(string path)
|
||||
{
|
||||
using var mod = ModuleDefinition.ReadModule(path, new(ReadingMode.Immediate) { ReadWrite = true });
|
||||
foreach (var typeDefinition in mod.Types)
|
||||
{
|
||||
typeDefinition.IsPublic = true;
|
||||
foreach (var method in typeDefinition.Methods) method.IsPublic = true;
|
||||
foreach (var field in typeDefinition.Fields) field.IsPublic = true;
|
||||
}
|
||||
|
||||
mod.Write();
|
||||
}
|
|
@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TechbloxModdingAPI", "Techb
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeGenerator", "CodeGenerator\CodeGenerator.csproj", "{0EBB6400-95A7-4A3D-B2ED-BF31E364CC10}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MakeEverythingPublicInGame", "MakeEverythingPublicInGame\MakeEverythingPublicInGame.csproj", "{391A3107-E5C6-4A04-9467-6D868AA9A8B4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -26,6 +28,12 @@ Global
|
|||
{0EBB6400-95A7-4A3D-B2ED-BF31E364CC10}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0EBB6400-95A7-4A3D-B2ED-BF31E364CC10}.Test|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0EBB6400-95A7-4A3D-B2ED-BF31E364CC10}.Test|Any CPU.Build.0 = Debug|Any CPU
|
||||
{391A3107-E5C6-4A04-9467-6D868AA9A8B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{391A3107-E5C6-4A04-9467-6D868AA9A8B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{391A3107-E5C6-4A04-9467-6D868AA9A8B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{391A3107-E5C6-4A04-9467-6D868AA9A8B4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{391A3107-E5C6-4A04-9467-6D868AA9A8B4}.Test|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{391A3107-E5C6-4A04-9467-6D868AA9A8B4}.Test|Any CPU.Build.0 = Debug|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
58
TechbloxModdingAPI/App/AntiAntiCheatPatch.cs
Normal file
58
TechbloxModdingAPI/App/AntiAntiCheatPatch.cs
Normal file
|
@ -0,0 +1,58 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using HarmonyLib;
|
||||
using Svelto.Tasks;
|
||||
using Techblox.Anticheat.Client;
|
||||
|
||||
namespace TechbloxModdingAPI.App
|
||||
{
|
||||
public static class AntiAntiCheatPatch
|
||||
{
|
||||
private delegate bool AntiAnticheatDelegate(ref object __result);
|
||||
|
||||
private delegate bool AntiAnticheatDelegateBool(ref bool __result);
|
||||
|
||||
private delegate bool AntiAnticheatDelegateTask(ref IEnumerator<TaskContract> __result);
|
||||
|
||||
public static void Init(Harmony harmony)
|
||||
{
|
||||
var type = AccessTools.TypeByName("Techblox.Services.Eos.Anticheat.Client.Services.AnticheatClientService");
|
||||
harmony.Patch(type.GetConstructors()[0], new HarmonyMethod(((Func<bool>) AntiAntiCheat).Method));
|
||||
harmony.Patch(AccessTools.Method(type, "Shutdown"), new HarmonyMethod(((Func<bool>) AntiAntiCheat).Method));
|
||||
harmony.Patch(AccessTools.Method(type, "StartProtectedSession"), new HarmonyMethod(((AntiAnticheatDelegate) AntiAntiCheat).Method));
|
||||
harmony.Patch(AccessTools.Method(type, "StopProtectedSession"), new HarmonyMethod(((AntiAnticheatDelegateBool) AntiAntiCheat).Method));
|
||||
harmony.Patch(AccessTools.Method("Techblox.Services.Eos.Anticheat.Client.EosGetPendingMessagesToSendServiceRequest:Execute"), new HarmonyMethod(((AntiAnticheatDelegateTask)AntiAntiCheatTask).Method));
|
||||
harmony.Patch(AccessTools.Method("Techblox.Anticheat.Client.Engines.ProcessEACViolationEngine:PollAnticheatStatus"), new HarmonyMethod(((AntiAnticheatDelegateTask)AntiAntiCheatTask).Method));
|
||||
harmony.Patch(AccessTools.Method(typeof(AnticheatClientCompositionRoot), "ClientComposeTimeRunning"), new HarmonyMethod(((Func<bool>)AntiAntiCheat).Method));
|
||||
}
|
||||
|
||||
private static bool AntiAntiCheat() => false;
|
||||
|
||||
private static bool AntiAntiCheat(ref object __result)
|
||||
{
|
||||
var targetType =
|
||||
AccessTools.TypeByName("Techblox.Services.Eos.Anticheat.Client.Services.StartProtectedSessionResult");
|
||||
var target = Activator.CreateInstance(targetType);
|
||||
targetType.GetField("Success").SetValue(target, true);
|
||||
__result = target;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool AntiAntiCheat(ref bool __result)
|
||||
{
|
||||
__result = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool AntiAntiCheatTask(ref IEnumerator<TaskContract> __result)
|
||||
{
|
||||
IEnumerator<TaskContract> Func()
|
||||
{
|
||||
yield return Yield.It;
|
||||
}
|
||||
|
||||
__result = Func();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
using System;
|
||||
|
||||
using RobocraftX.GUI.MyGamesScreen;
|
||||
using Svelto.ECS;
|
||||
using TechbloxModdingAPI.Engines;
|
||||
using TechbloxModdingAPI.Utility;
|
||||
|
||||
namespace TechbloxModdingAPI.App
|
||||
{
|
||||
public class AppEngine : IFactoryEngine
|
||||
{
|
||||
public WrappedHandler<MenuEventArgs> EnterMenu;
|
||||
|
||||
public WrappedHandler<MenuEventArgs> ExitMenu;
|
||||
|
||||
public IEntityFactory Factory { set; private get; }
|
||||
|
||||
public string Name => "TechbloxModdingAPIAppEngine";
|
||||
|
||||
public bool isRemovable => false;
|
||||
|
||||
public EntitiesDB entitiesDB { set; private get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
IsInMenu = false;
|
||||
ExitMenu.Invoke(this, new MenuEventArgs { });
|
||||
}
|
||||
|
||||
public void Ready()
|
||||
{
|
||||
IsInMenu = true;
|
||||
EnterMenu.Invoke(this, new MenuEventArgs { });
|
||||
}
|
||||
|
||||
// app functionality
|
||||
|
||||
public bool IsInMenu
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = false;
|
||||
}
|
||||
}
|
|
@ -14,12 +14,12 @@ namespace TechbloxModdingAPI.App
|
|||
/// </summary>
|
||||
public class Client
|
||||
{
|
||||
public static Client Instance { get; } = new Client();
|
||||
|
||||
protected static Func<object> ErrorHandlerInstanceGetter;
|
||||
|
||||
protected static Action<object, Error> EnqueueError;
|
||||
|
||||
protected static Action<object> HandleErrorClosed;
|
||||
|
||||
/// <summary>
|
||||
/// An event that fires whenever the main menu is loaded.
|
||||
/// </summary>
|
||||
|
@ -93,14 +93,26 @@ namespace TechbloxModdingAPI.App
|
|||
EnqueueError(errorHandlerInstance, popup);
|
||||
}
|
||||
|
||||
// TODO
|
||||
/*public void CloseCurrentPrompt()
|
||||
public void CloseCurrentPrompt()
|
||||
{
|
||||
// RobocraftX.Services.ErrorHandler.Instance.HandlePopupClosed();
|
||||
// FIXME: this is a call that is also called when closing, not the actual closing action itself (so it doesn't work)
|
||||
object errorHandlerInstance = ErrorHandlerInstanceGetter();
|
||||
HandleErrorClosed(errorHandlerInstance);
|
||||
}*/
|
||||
var popup = GetPopupCloseMethods(errorHandlerInstance);
|
||||
popup.Close();
|
||||
}
|
||||
|
||||
public void SelectFirstPromptButton()
|
||||
{
|
||||
object errorHandlerInstance = ErrorHandlerInstanceGetter();
|
||||
var popup = GetPopupCloseMethods(errorHandlerInstance);
|
||||
popup.FirstButton();
|
||||
}
|
||||
|
||||
public void SelectSecondPromptButton()
|
||||
{
|
||||
object errorHandlerInstance = ErrorHandlerInstanceGetter();
|
||||
var popup = GetPopupCloseMethods(errorHandlerInstance);
|
||||
popup.SecondButton();
|
||||
}
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
|
@ -113,9 +125,6 @@ namespace TechbloxModdingAPI.App
|
|||
EnqueueError = (Action<object, Error>) AccessTools.Method("TechbloxModdingAPI.App.Client:GenEnqueueError")
|
||||
.MakeGenericMethod(errorHandler, errorHandle)
|
||||
.Invoke(null, new object[0]);
|
||||
/*HandleErrorClosed = (Action<object>) AccessTools.Method("TechbloxModdingAPI.App.Client:GenHandlePopupClosed")
|
||||
.MakeGenericMethod(errorHandler)
|
||||
.Invoke(null, new object[0]);*/
|
||||
}
|
||||
|
||||
// Creating delegates once is faster than reflection every time
|
||||
|
@ -140,14 +149,23 @@ namespace TechbloxModdingAPI.App
|
|||
return enqueueCasted;
|
||||
}
|
||||
|
||||
private static Action<object> GenHandlePopupClosed<T>()
|
||||
private static (Action Close, Action FirstButton, Action SecondButton) _errorPopup;
|
||||
|
||||
private static (Action Close, Action FirstButton, Action SecondButton) GetPopupCloseMethods(object handler)
|
||||
{
|
||||
Type errorHandler = AccessTools.TypeByName("RobocraftX.Services.ErrorHandler");
|
||||
MethodInfo handlePopupClosed = AccessTools.Method(errorHandler, "HandlePopupClosed");
|
||||
Action<T> handleSimple =
|
||||
(Action<T>) Delegate.CreateDelegate(typeof(Action<T>), handlePopupClosed);
|
||||
Action<object> handleCasted = (object instance) => handleSimple((T) instance);
|
||||
return handleCasted;
|
||||
if (_errorPopup.Close != null)
|
||||
return _errorPopup;
|
||||
Type errorHandler = handler.GetType();
|
||||
FieldInfo field = AccessTools.Field(errorHandler, "errorPopup");
|
||||
var errorPopup = (ErrorPopup)field.GetValue(handler);
|
||||
MethodInfo info = AccessTools.Method(errorPopup.GetType(), "ClosePopup");
|
||||
var close = (Action)Delegate.CreateDelegate(typeof(Action), errorPopup, info);
|
||||
info = AccessTools.Method(errorPopup.GetType(), "HandleFirstOption");
|
||||
var first = (Action)Delegate.CreateDelegate(typeof(Action), errorPopup, info);
|
||||
info = AccessTools.Method(errorPopup.GetType(), "HandleSecondOption");
|
||||
var second = (Action)Delegate.CreateDelegate(typeof(Action), errorPopup, info);
|
||||
_errorPopup = (close, first, second);
|
||||
return _errorPopup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,17 +42,25 @@ namespace TechbloxModdingAPI.App
|
|||
[APITestCase(TestType.Menu)]
|
||||
public static void TestPopUp2()
|
||||
{
|
||||
Client c = new Client();
|
||||
c.PromptUser(popup2);
|
||||
//c.CloseCurrentPrompt();
|
||||
Client.Instance.PromptUser(popup2);
|
||||
}
|
||||
|
||||
[APITestCase(TestType.Menu)]
|
||||
public static void TestPopUp1()
|
||||
{
|
||||
Client c = new Client();
|
||||
c.PromptUser(popup1);
|
||||
//c.CloseCurrentPrompt();
|
||||
Client.Instance.PromptUser(popup1);
|
||||
}
|
||||
|
||||
[APITestCase(TestType.Menu)]
|
||||
public static void TestPopUpClose1()
|
||||
{
|
||||
Client.Instance.CloseCurrentPrompt();
|
||||
}
|
||||
|
||||
[APITestCase(TestType.Menu)]
|
||||
public static void TestPopUpClose2()
|
||||
{
|
||||
Client.Instance.CloseCurrentPrompt();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,23 +1,27 @@
|
|||
namespace TechbloxModdingAPI.App
|
||||
using System;
|
||||
|
||||
namespace TechbloxModdingAPI.App
|
||||
{
|
||||
public enum CurrentGameMode
|
||||
{
|
||||
None,
|
||||
/// <summary>
|
||||
/// Building a game
|
||||
/// Building a world
|
||||
/// </summary>
|
||||
Build,
|
||||
/// <summary>
|
||||
/// Playing a game
|
||||
/// Playing on a map
|
||||
/// </summary>
|
||||
Play,
|
||||
/// <summary>
|
||||
/// Viewing a prefab
|
||||
/// Viewing a prefab (doesn't exist anymore)
|
||||
/// </summary>
|
||||
[Obsolete]
|
||||
View,
|
||||
/// <summary>
|
||||
/// Viewing a tutorial
|
||||
/// Viewing a tutorial (doesn't exist anymore)
|
||||
/// </summary>
|
||||
[Obsolete]
|
||||
Tutorial
|
||||
}
|
||||
}
|
|
@ -2,12 +2,10 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
using RobocraftX.Common;
|
||||
using RobocraftX.GUI.MyGamesScreen;
|
||||
using RobocraftX.StateSync;
|
||||
using Svelto.ECS;
|
||||
using Techblox.GameSelection;
|
||||
|
||||
using TechbloxModdingAPI;
|
||||
using TechbloxModdingAPI.Blocks;
|
||||
using TechbloxModdingAPI.Tasks;
|
||||
using TechbloxModdingAPI.Utility;
|
||||
|
@ -318,7 +316,7 @@ namespace TechbloxModdingAPI.App
|
|||
get
|
||||
{
|
||||
if (menuMode || !VerifyMode()) return CurrentGameMode.None;
|
||||
return (CurrentGameMode) GameMode.CurrentMode;
|
||||
return gameEngine.GetGameData().gameMode == GameMode.CreateWorld ? CurrentGameMode.Build : CurrentGameMode.Play;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
using HarmonyLib;
|
||||
using RobocraftX;
|
||||
using RobocraftX.Common;
|
||||
using RobocraftX.Schedulers;
|
||||
using RobocraftX.SimulationModeState;
|
||||
|
@ -8,11 +10,15 @@ using Svelto.Tasks;
|
|||
using Svelto.Tasks.Lean;
|
||||
using RobocraftX.Blocks;
|
||||
using RobocraftX.Common.Loading;
|
||||
using RobocraftX.Multiplayer;
|
||||
using RobocraftX.ScreenshotTaker;
|
||||
using Techblox.Environment.Transition;
|
||||
using Techblox.GameSelection;
|
||||
|
||||
using TechbloxModdingAPI.Blocks;
|
||||
using TechbloxModdingAPI.Engines;
|
||||
using TechbloxModdingAPI.Input;
|
||||
using TechbloxModdingAPI.Players;
|
||||
using TechbloxModdingAPI.Utility;
|
||||
|
||||
namespace TechbloxModdingAPI.App
|
||||
|
@ -30,16 +36,34 @@ namespace TechbloxModdingAPI.App
|
|||
public EntitiesDB entitiesDB { set; private get; }
|
||||
|
||||
private bool enteredGame;
|
||||
private bool loadingFinished;
|
||||
private bool playerJoined;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (GameReloadedPatch.IsReload)
|
||||
return; // Toggling time mode
|
||||
ExitGame.Invoke(this, new GameEventArgs { GameName = GetGameData().saveName, GamePath = GetGameData().gameID });
|
||||
IsInGame = false;
|
||||
loadingFinished = false;
|
||||
playerJoined = false;
|
||||
enteredGame = false;
|
||||
}
|
||||
|
||||
public void Ready()
|
||||
{
|
||||
if (GameReloadedPatch.IsReload)
|
||||
return; // Toggling time mode
|
||||
enteredGame = true;
|
||||
Player.Joined += OnPlayerJoined;
|
||||
}
|
||||
|
||||
private void OnPlayerJoined(object sender, PlayerEventArgs args)
|
||||
{
|
||||
if (args.Player.Type != PlayerType.Local) return;
|
||||
playerJoined = true;
|
||||
Player.Joined -= OnPlayerJoined;
|
||||
CheckJoinEvent();
|
||||
}
|
||||
|
||||
// game functionality
|
||||
|
@ -54,7 +78,7 @@ namespace TechbloxModdingAPI.App
|
|||
{
|
||||
if (async)
|
||||
{
|
||||
ExitCurrentGameAsync().RunOn(Lean.EveryFrameStepRunner_TimeRunningAndStopped);
|
||||
ExitCurrentGameAsync().RunOn(ClientLean.EveryFrameStepRunner_TimeRunningAndStopped);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -94,27 +118,41 @@ namespace TechbloxModdingAPI.App
|
|||
|
||||
public void ToggleTimeMode()
|
||||
{
|
||||
if (!entitiesDB.FoundInGroups<BlockTagEntityStruct>())
|
||||
throw new AppStateException("At least one block must exist in the world to enter simulation");
|
||||
SwitchAnimationUtil.Start(entitiesDB);
|
||||
}
|
||||
if (TimeRunningModeUtil.IsTimeStoppedMode(entitiesDB))
|
||||
FakeInput.ActionInput(toggleMode: true);
|
||||
else
|
||||
{
|
||||
IEnumerator<TaskContract> ReloadBuildModeTask()
|
||||
{
|
||||
SwitchAnimationUtil.Start(entitiesDB);
|
||||
while (SwitchAnimationUtil.IsFadeOutActive(entitiesDB))
|
||||
yield return (TaskContract)Yield.It;
|
||||
FullGameFields._multiplayerParams.MultiplayerMode = MultiplayerMode.SinglePlayer;
|
||||
AccessTools.Method(typeof(FullGameCompositionRoot), "ReloadGame")
|
||||
.Invoke(FullGameFields.Instance, new object[] { });
|
||||
}
|
||||
|
||||
ReloadBuildModeTask().RunOn(ClientLean.UIScheduler);
|
||||
}
|
||||
}
|
||||
|
||||
public EGID[] GetAllBlocksInGame(BlockIDs filter = BlockIDs.Invalid)
|
||||
{
|
||||
var allBlocks = entitiesDB.QueryEntities<BlockTagEntityStruct>();
|
||||
List<EGID> blockEGIDs = new List<EGID>();
|
||||
foreach (var (blocks, _) in allBlocks)
|
||||
foreach (var ((_, ids, count), group) in allBlocks)
|
||||
{
|
||||
var (buffer, count) = blocks.ToBuffer();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var id = new EGID(ids[i], group);
|
||||
uint dbid;
|
||||
if (filter == BlockIDs.Invalid)
|
||||
dbid = (uint)filter;
|
||||
else
|
||||
dbid = entitiesDB.QueryEntity<DBEntityStruct>(buffer[i].ID).DBID;
|
||||
if (dbid == (ulong)filter)
|
||||
blockEGIDs.Add(buffer[i].ID);
|
||||
dbid = entitiesDB.QueryEntity<DBEntityStruct>(id).DBID;
|
||||
var ownership = entitiesDB.QueryEntity<BlockOwnershipComponent>(id).BlockOwnership;
|
||||
if ((ownership & BlockOwnership.User) != 0 && dbid == (ulong)filter)
|
||||
blockEGIDs.Add(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,9 +180,16 @@ namespace TechbloxModdingAPI.App
|
|||
public void Remove(ref LoadingActionEntityStruct entityComponent, EGID egid)
|
||||
{ // Finished loading
|
||||
if (!enteredGame) return;
|
||||
enteredGame = false;
|
||||
loadingFinished = true;
|
||||
CheckJoinEvent();
|
||||
}
|
||||
|
||||
private void CheckJoinEvent()
|
||||
{
|
||||
if (!loadingFinished || !playerJoined) return;
|
||||
EnterGame.Invoke(this, new GameEventArgs { GameName = GetGameData().saveName, GamePath = GetGameData().gameID });
|
||||
IsInGame = true;
|
||||
enteredGame = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,16 +3,15 @@ using System.Reflection;
|
|||
using HarmonyLib;
|
||||
|
||||
using RobocraftX;
|
||||
using RobocraftX.Common;
|
||||
using RobocraftX.FrontEnd;
|
||||
using RobocraftX.GUI;
|
||||
using RobocraftX.GUI.MyGamesScreen;
|
||||
using RobocraftX.Multiplayer;
|
||||
using Svelto.ECS;
|
||||
using Svelto.ECS.Experimental;
|
||||
using Techblox.GameSelection;
|
||||
|
||||
using TechbloxModdingAPI.Engines;
|
||||
using TechbloxModdingAPI.Utility;
|
||||
using GameMode = RobocraftX.Common.GameMode;
|
||||
|
||||
namespace TechbloxModdingAPI.App
|
||||
{
|
||||
|
@ -56,13 +55,12 @@ namespace TechbloxModdingAPI.App
|
|||
|
||||
public Game[] GetMyGames()
|
||||
{
|
||||
EntityCollection<MyGameDataEntityStruct> mgsevs = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames);
|
||||
var mgsevsB = mgsevs.ToBuffer().buffer;
|
||||
Game[] games = new Game[mgsevs.count];
|
||||
for (int i = 0; i < mgsevs.count; i++)
|
||||
var (mgsevs, count) = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames);
|
||||
Game[] games = new Game[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Utility.Logging.MetaDebugLog($"Found game named {mgsevsB[i].GameName}");
|
||||
games[i] = new Game(mgsevsB[i].ID);
|
||||
Utility.Logging.MetaDebugLog($"Found game named {mgsevs[i].GameName}");
|
||||
games[i] = new Game(mgsevs[i].ID);
|
||||
}
|
||||
return games;
|
||||
}
|
||||
|
@ -85,14 +83,13 @@ namespace TechbloxModdingAPI.App
|
|||
|
||||
public uint HighestID()
|
||||
{
|
||||
EntityCollection<MyGameDataEntityStruct> games = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames);
|
||||
var gamesB = games.ToBuffer().buffer;
|
||||
var (games, count) = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames);
|
||||
uint max = 0;
|
||||
for (int i = 0; i < games.count; i++)
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (gamesB[i].ID.entityID > max)
|
||||
if (games[i].ID.entityID > max)
|
||||
{
|
||||
max = gamesB[i].ID.entityID;
|
||||
max = games[i].ID.entityID;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
|
@ -105,20 +102,16 @@ namespace TechbloxModdingAPI.App
|
|||
return EnterGame(mgdes.GameName, mgdes.FileId);
|
||||
}
|
||||
|
||||
public bool EnterGame(string gameName, string fileId, bool autoEnterSim = false)
|
||||
public bool EnterGame(ECSString gameName, string fileId, bool autoEnterSim = false)
|
||||
{
|
||||
GameMode.CurrentMode = autoEnterSim ? RCXMode.Play : RCXMode.Build;
|
||||
var data = new GameSelectionData
|
||||
{
|
||||
gameMode = Techblox.GameSelection.GameMode.PlayGame,
|
||||
gameType = GameType.MachineEditor,
|
||||
saveName = gameName,
|
||||
saveType = SaveType.ExistingSave,
|
||||
gameID = "GAMEID_Road_Track", //TODO: Expose to the API
|
||||
userContentID = fileId
|
||||
};
|
||||
// the private FullGameCompositionRoot.SwitchToGame() method gets passed to menu items for this reason
|
||||
AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToGame").Invoke(FullGameFields.Instance, new object[]{data});
|
||||
FullGameFields._multiplayerParams.MultiplayerMode = MultiplayerMode.SinglePlayer;
|
||||
ref var selection = ref entitiesDB.QueryEntity<GameSelectionComponent>(GameSelectionConstants.GameSelectionEGID);
|
||||
selection.userContentID.Set(fileId);
|
||||
selection.triggerStart = true;
|
||||
selection.saveType = SaveType.ExistingSave;
|
||||
selection.saveName = gameName;
|
||||
selection.gameMode = GameMode.PlayGame;
|
||||
selection.gameID.Set("GAMEID_Road_Track"); //TODO: Expose to the API
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -178,7 +171,7 @@ namespace TechbloxModdingAPI.App
|
|||
|
||||
public static MethodBase TargetMethod()
|
||||
{
|
||||
return AccessTools.Method(typeof(FullGameCompositionRoot), "GoToMenu");
|
||||
return AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToMenu");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,10 +8,10 @@ using Svelto.ECS.EntityStructs;
|
|||
using RobocraftX.Common;
|
||||
using RobocraftX.Blocks;
|
||||
using Unity.Mathematics;
|
||||
using Gamecraft.Blocks.GUI;
|
||||
using HarmonyLib;
|
||||
using RobocraftX.PilotSeat;
|
||||
|
||||
using RobocraftX.Rendering;
|
||||
using Techblox.BlockLabelsServer;
|
||||
using TechbloxModdingAPI.Blocks;
|
||||
using TechbloxModdingAPI.Blocks.Engines;
|
||||
using TechbloxModdingAPI.Tests;
|
||||
|
@ -67,7 +67,7 @@ namespace TechbloxModdingAPI
|
|||
/// <returns>The block object or null if doesn't exist</returns>
|
||||
public static Block GetLastPlacedBlock()
|
||||
{
|
||||
uint lastBlockID = (uint) AccessTools.Field(typeof(CommonExclusiveGroups), "_nextBlockEntityID").GetValue(null) - 1;
|
||||
uint lastBlockID = CommonExclusiveGroups.blockIDGeneratorClient.Peek() - 1;
|
||||
EGID? egid = BlockEngine.FindBlockEGID(lastBlockID);
|
||||
return egid.HasValue ? New(egid.Value) : null;
|
||||
}
|
||||
|
@ -288,6 +288,7 @@ namespace TechbloxModdingAPI
|
|||
color.indexInPalette = value.Index;
|
||||
color.hasNetworkChange = true;
|
||||
color.paletteColour = BlockEngine.ConvertBlockColor(color.indexInPalette); //Setting to 255 results in black
|
||||
BlockEngine.UpdateBlockColor(Id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,11 +340,15 @@ namespace TechbloxModdingAPI
|
|||
[TestValue(null)]
|
||||
public string Label
|
||||
{
|
||||
get => BlockEngine.GetBlockInfoViewComponent<TextLabelEntityViewStruct>(this).textLabelComponent?.text;
|
||||
get
|
||||
{
|
||||
var opt = BlockEngine.GetBlockInfoOptional<LabelResourceIDComponent>(this);
|
||||
return opt ? FullGameFields._managers.blockLabelResourceManager.GetText(opt.Get().instanceID) : null;
|
||||
}
|
||||
set
|
||||
{
|
||||
var comp = BlockEngine.GetBlockInfoViewComponent<TextLabelEntityViewStruct>(this).textLabelComponent;
|
||||
if (comp != null) comp.text = value;
|
||||
var opt = BlockEngine.GetBlockInfoOptional<LabelResourceIDComponent>(this);
|
||||
if (opt) FullGameFields._managers.blockLabelResourceManager.SetText(opt.Get().instanceID, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -361,8 +366,12 @@ namespace TechbloxModdingAPI
|
|||
get
|
||||
{
|
||||
if (blockGroup != null) return blockGroup;
|
||||
if (!GameState.IsBuildMode()) return null; // Breaks in simulation
|
||||
var bgec = BlockEngine.GetBlockInfo<BlockGroupEntityComponent>(this);
|
||||
return blockGroup = bgec.currentBlockGroup == -1 ? null : new BlockGroup(bgec.currentBlockGroup, this);
|
||||
return blockGroup = bgec.currentBlockGroup == -1
|
||||
? null
|
||||
: GetInstance(new EGID((uint)bgec.currentBlockGroup, BlockGroupExclusiveGroups.BlockGroupEntityGroup),
|
||||
egid => new BlockGroup((int)egid.entityID, this));
|
||||
}
|
||||
set
|
||||
{
|
||||
|
@ -390,6 +399,23 @@ namespace TechbloxModdingAPI
|
|||
set => BlockEngine.GetBlockInfo<BlockStaticComponent>(this).isStatic = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The mass of the block.
|
||||
/// </summary>
|
||||
public float Mass
|
||||
{
|
||||
get => BlockEngine.GetBlockInfo<MassStruct>(this).mass;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Block complexity used for build rules. Determines the 'cost' of the block.
|
||||
/// </summary>
|
||||
public BlockComplexity Complexity
|
||||
{
|
||||
get => new(BlockEngine.GetBlockInfo<BlockComplexityComponent>(this));
|
||||
set => BlockEngine.GetBlockInfo<BlockComplexityComponent>(this) = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the block exists. The other properties will return a default value if the block doesn't exist.
|
||||
/// If the block was just placed, then this will also return false but the properties will work correctly.
|
||||
|
@ -415,9 +441,10 @@ namespace TechbloxModdingAPI
|
|||
public SimBody GetSimBody()
|
||||
{
|
||||
var st = BlockEngine.GetBlockInfo<GridConnectionsEntityStruct>(this);
|
||||
return st.machineRigidBodyId != uint.MaxValue
|
||||
? new SimBody(st.machineRigidBodyId, st.clusterId)
|
||||
: null;
|
||||
/*return st.machineRigidBodyId != uint.MaxValue
|
||||
? new SimBody(st.machineRigidBodyId, st.clusterId) - TODO:
|
||||
: null;*/
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
|
17
TechbloxModdingAPI/Blocks/BlockComplexity.cs
Normal file
17
TechbloxModdingAPI/Blocks/BlockComplexity.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using RobocraftX.Blocks;
|
||||
|
||||
namespace TechbloxModdingAPI.Blocks
|
||||
{
|
||||
public record BlockComplexity(int Cpu, int Power)
|
||||
{
|
||||
public BlockComplexity(BlockComplexityComponent component) : this(component.cpu, component.power)
|
||||
{
|
||||
}
|
||||
|
||||
public int Cpu { get; } = Cpu;
|
||||
public int Power { get; } = Power;
|
||||
|
||||
public static implicit operator BlockComplexityComponent(BlockComplexity complexity) =>
|
||||
new() { cpu = complexity.Cpu, power = complexity.Power };
|
||||
}
|
||||
}
|
|
@ -273,6 +273,111 @@ namespace TechbloxModdingAPI.Blocks
|
|||
/// <summary>
|
||||
/// The grid block used by the world editor, named Small Grid like the other one
|
||||
/// </summary>
|
||||
SmallGridInWorldEditor
|
||||
SmallGridInWorldEditor,
|
||||
CityDoubleCrossing,
|
||||
CityDoubleCrossroads,
|
||||
CitySmallDoubleJunction,
|
||||
CityDoubleJunction,
|
||||
CityDoubleToSingleJunction,
|
||||
CitySmallDoubleRoad,
|
||||
CityDoubleRoad,
|
||||
CitySmallDoubleTurn,
|
||||
CityLargeDoubleTurn,
|
||||
CitySmallSingleTurn,
|
||||
CityLargeSingleTurn,
|
||||
CitySingleJunction,
|
||||
CitySingleRoad,
|
||||
SegoeUITextblock,
|
||||
GravtracTextblock,
|
||||
HauserTextblock,
|
||||
TechnopollasTextblock,
|
||||
CityDoubleHillRoad,
|
||||
DiagonalTrackTile,
|
||||
DiagonalTrackTile2,
|
||||
DiagonalTransitionTile,
|
||||
SplitLane,
|
||||
BitBlock,
|
||||
Timer,
|
||||
CityNightAtmosphere,
|
||||
FloodLight,
|
||||
SoccerBall,
|
||||
CircularWallLight,
|
||||
BlueSkyAtmos,
|
||||
DirtToGrassTransitionTile = 393,
|
||||
DirtToGrassTransitionInnerTile,
|
||||
DirtToGrassTransitionOuterTile,
|
||||