Compare commits

...

64 commits

Author SHA1 Message Date
5dff88d703
Switch from IPA to BepInEx
- Removed a bunch of test code
- Preparing for 3.0
2023-08-22 00:02:26 +02:00
a8a451f8e4
Merge TB update feature branch 2023-03-30 01:22:10 +02:00
67f32b8810
Improved and fixed publish queue detection and block test
- Made the PublishEntityChangesDelayed() method use the internals of Svelto.ECS to determine if it should wait
-- I had this code for a while but it used too much reflection to my liking
-- Now I made the reflection code nicer and a bit safer
- Fixed float comparisons: last time I didn't actually used abs() for float3 but I found this even better method
2023-03-30 01:17:31 +02:00
b3b1e9b9e7
Update reference paths to allow for RC2 dev as well 2022-10-18 20:19:41 +02:00
e0cd7f6aec
Fix assembly editing and add more of it
- It breaks the game atm, not sure why exactly but it's probably not a good thing
2022-10-05 01:53:54 +02:00
23439abde3
Add new blocks and materials, make every type public in the game, fix entity publish
- Probably should've committed more
- Added new block IDs and a material (also fixed material names)
- Added missing player states
- Added a class to make every type public in the game's code, so we don't need to worry about internal components
- We don't need to worry about anticheat so it should be fine - will need to be made into its own exe though
- Fixed delayed entity publishing and set the limits based on the consumers (just 30 almost everywhere)
2022-10-04 01:47:09 +02:00
5e90c5ee26
Fix all compiler issues and add Count property and smart ToArray() function to RefCollection
- Collections can be converted into arrays using a mapper and a predicate function
2022-10-02 01:34:51 +02:00
5117b69500
Fix RefCollection and start using it to query multiple users
- I overcomplicated in the beginning
- It doesn't shorten the code that much but it provides a stable interface and it's easier to use so I guess it's nice
2022-09-29 01:26:51 +02:00
f70b65e796
Start updating to Techblox 2022.08.11.09.42 and start work on RefCollection
What have I got myself into
2022-09-29 00:29:12 +02:00
55344d1352
Start updating to Techblox 2022.05.25.11.05
Resolved compiler errors
Mostly by removing erroring code
2022-06-01 16:54:17 +02:00
dfe1bfb504
Begin updating to Techblox 2022.04.28.14.02
Updated project generator script to always order assemblies (it didn't do that for me on Linux) and to fix minor issues
2022-04-29 02:07:46 +02:00
a610623644 Bump version 2022-04-12 03:18:28 +02:00
f9aa6ce2bb Re-add object ID class, add some wheel rig properties, remove old game assembly refernces 2022-04-12 00:52:24 +02:00
23abe47c72 Update to Techblox 2022.04.01.10.32
- Updated project to use .NET Standard 2.1, which is what the game uses
- Updated CodeGenerator to use .NET 6
2022-04-08 03:25:05 +02:00
c0ef8f1fae Fix support for accessing properties using reflection
The test still crashes the game
2022-03-27 03:49:45 +02:00
c4a9125ed3 Update to Techblox 2022.03.17.17.24 2022-03-20 18:08:16 +01:00
3eecdf2cf5 Add key collection to weak dictionary and compact code 2022-02-24 01:02:35 +01:00
2db7b607f0 Improve UI elements (IMGUI) 2022-02-23 02:25:34 +01:00
7f63944a6e Block fixes, add mass and complexity properties, make Player.LocalPlayer return null if not found 2022-02-19 02:25:58 +01:00
c6dae688fe Update to Techblox 2022.02.17.10.32 2022-02-18 23:09:56 +01:00
7b2ac973d8 Bump version to v2.2.0 2022-02-13 20:21:42 +01:00
0ec47cd38b Add method to get ghost block 2022-02-13 18:27:54 +01:00
ddaa933e7d Add option to delay entity change publish and remove reflection stuff
Neither of them work actually
Added some delay between tests
2022-02-07 00:25:01 +01:00
5fea7dc3b3 Add support for generating block classes that use reflection to access internal components
Added Engine properties again
2022-02-06 03:11:51 +01:00
4684b33c69 Fix tests, getting machine blocks, block labels and visuals
- Checking the material property again, it seems to work now
- Fixed the Seat events not triggering during tests (the player in build and in sim is different)
- Fixed Game.GetAllBlocksInGame() returning environment blocks (since a Game refers to a machine save)
- Fixed the Block.Label property
- Fixed the block visuals not being updated after applying changes
2022-01-31 23:20:03 +01:00
d27bcee8d5 Update to Techblox 2022.01.25.15.52
- Fixed compilation errors
- Fixed patching errors and added missing anti-cheat patch
- Added check to verify that the init data has been removed from blocks once they are placed in game
- Removed block place event deduplication as it seems to be not needed anymore
- Fixed async tests not properly running
- Added Player.State
- Attempted to fix seat entering/leaving (we can only send inputs in client code)
- Fixed the weak dictionary ContainsKey returning true even if the item is no longer there
2022-01-30 04:32:10 +01:00
09d3c5e81c Merge branch 'preview'
# Conflicts:
#	Automation/gen_csproj.py
#	TechbloxModdingAPI/TechbloxModdingAPI.csproj
2022-01-29 20:53:07 +01:00
966fdd4c3a Fix even more issues uncovered by tests
- Fixed the time mode toggle not working during testing (changed the runner)
- Made the testing thing wait until the time toggle finishes
- Fixed the Game.Enter/Exit event being triggered on time mode change
- Added a way to spawn and despawn the player's machine (which doesn't work yet)
- Fixed the Player.Id property always being 0
- Attempted to fix the fake action inputs not working in simulation
2022-01-07 02:14:58 +01:00
5602ef9268 All kinds of fixes of issues during automatic tests
- Fixed toggling time running mode
- Fixed closing popups
- Added support for pressing the buttons on a popup
- Added error handling to Main.Init()
- Automatically closing the beta message in the test plugin
- Fixed Game.EnterGame() causing a crash in the game
2021-12-28 15:09:01 +01:00
93a0b2287a Added player join/leave events and fix errors
- Fixed anticheat status error spam
- Fixed IMGUI not actually running on OnGUI because that runner was changed in Svelto
- Added player join and leave events
- Made Game.Enter only trigger when both the game has finished loading *and* the local player has joined
2021-12-27 02:28:09 +01:00
4ac8d53a2d Organize anti-anticheat, add block IDs, fix crash when adding event handlers multiple times 2021-12-26 23:37:02 +01:00
f817becc6e Resolve all compile-time and patching errors, remove anticheat in singleplayer 2021-12-16 21:13:45 +01:00
2a1782cd82 Start updating to 2021.12.14.17.00
A bunch of errors still
2021-12-15 03:46:38 +01:00
fef66c349d Merge branch 'master' into preview
# Conflicts:
#	Automation/gen_csproj.py
#	GamecraftModdingAPI/App/AppEngine.cs
#	GamecraftModdingAPI/App/GameGameEngine.cs
#	GamecraftModdingAPI/App/GameMenuEngine.cs
#	GamecraftModdingAPI/Block.cs
#	GamecraftModdingAPI/Blocks/BlockEngine.cs
#	GamecraftModdingAPI/Blocks/BlockEngineInit.cs
#	GamecraftModdingAPI/Blocks/BlockEventsEngine.cs
#	GamecraftModdingAPI/Blocks/BlockIDs.cs
#	GamecraftModdingAPI/Blocks/ConsoleBlock.cs
#	GamecraftModdingAPI/Blocks/DampedSpring.cs
#	GamecraftModdingAPI/Blocks/LogicGate.cs
#	GamecraftModdingAPI/Blocks/Motor.cs
#	GamecraftModdingAPI/Blocks/MusicBlock.cs
#	GamecraftModdingAPI/Blocks/ObjectIdentifier.cs
#	GamecraftModdingAPI/Blocks/Piston.cs
#	GamecraftModdingAPI/Blocks/PlacementEngine.cs
#	GamecraftModdingAPI/Blocks/Servo.cs
#	GamecraftModdingAPI/Blocks/SfxBlock.cs
#	GamecraftModdingAPI/Blocks/SpawnPoint.cs
#	GamecraftModdingAPI/Blocks/TextBlock.cs
#	GamecraftModdingAPI/Blocks/Timer.cs
#	GamecraftModdingAPI/GamecraftModdingAPI.csproj
#	GamecraftModdingAPI/Inventory/HotbarEngine.cs
#	GamecraftModdingAPI/Inventory/HotbarSlotSelectionHandlerEnginePatch.cs
#	GamecraftModdingAPI/Main.cs
#	GamecraftModdingAPI/Player.cs
#	GamecraftModdingAPI/Players/PlayerEngine.cs
#	GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs
#	TechbloxModdingAPI/BlockGroup.cs
#	TechbloxModdingAPI/Blocks/Engines/BlueprintEngine.cs
#	TechbloxModdingAPI/Blocks/Engines/RemovalEngine.cs
#	TechbloxModdingAPI/Blocks/Engines/SignalEngine.cs
#	TechbloxModdingAPI/Blueprint.cs
#	TechbloxModdingAPI/Input/FakeInput.cs
2021-12-14 23:26:35 +01:00
4580ae3b66 Add ability to create & move block groups & other stuff
Added a way to store block groups as blueprints
Blocks can be added/removed from block groups, although it doesn't work well atm
Added some patches to the test class in an attempt to debug an unrelated issue
Added a command to test placing a block group
Added a SelectedBlueprint property to the Player class
2020-11-12 02:39:58 +01:00
f1376f5df6 Replace ToManagedArray() and fix getting blocks from group 2020-11-10 23:08:27 +01:00
2179ba6386 Add support for setting and placing blueprints 2020-11-10 19:28:36 +01:00
1a986056a1 Add new blocks and some blueprint/block group support 2020-11-10 16:37:20 +01:00
NGnius (Graham)
d891f12701 Fix harmony patch error due to fixed name 2020-11-09 16:33:12 -05:00
NGnius (Graham)
1cb663b4d1 Fix build errors from beta hotfix 1 2020-11-09 16:18:25 -05:00
0bd348bd47
Fix initial issues and add error on patch fail
Fixed compilation and loading issues for 2020.10.27.17.13
2020-10-29 00:37:47 +01:00
3929144171
Merge remote-tracking branch 'origin/master' into preview
# Conflicts:
#	GamecraftModdingAPI/Block.cs
#	GamecraftModdingAPI/GamecraftModdingAPI.csproj
2020-10-28 21:10:30 +01:00
92965404ce Remove ScalingEngine.Setup() and add object ID to dict 2020-10-02 01:54:59 +02:00
58cfba443e Add hotfix blocks and Player.LocalPlayer 2020-09-30 23:52:17 +02:00
ee6a0e3af6 Add support for getting the RGB of block colors
Only works if the constructors are used
2020-09-28 03:10:59 +02:00
NGnius (Graham)
9e6edc19bd Implement SFX block API and bump version 2020-09-23 15:31:54 -04:00
d581ec598a Add the rest of the blocks 2020-09-19 00:13:05 +02:00
1e9d1c8f81 Fix TextBlock.Text=null, most new blocks and others 2020-09-18 21:19:39 +02:00
53bdd27166 Merge master into preview 2020-09-18 17:10:01 +02:00
2172364d26 Fixes, block IDs, cluster & chunk health support 2020-08-13 16:59:13 +02:00
NGnius (Graham)
50ebf4f0a6 Fix build issues for latest Gamecraft preview version 2020-08-07 13:55:00 -04:00
NGnius (Graham)
167ea5388b Merge branch 'master' into preview 2020-08-07 12:23:16 -04:00
47126d2d79
Update music block and attempt to fix test 2020-07-21 02:36:11 +02:00
c5e9599c46
Merge branch 'delegating' into preview 2020-07-21 00:24:50 +02:00
3f2139d592
Add some info and prev. value for setters 2020-07-21 00:19:30 +02:00
NGnius (Graham)
9e47bbcd9a Add popup UI method to Client 2020-07-19 20:05:01 -04:00
NGnius (Graham)
cda57afade Add sfx block support 2020-07-19 16:39:35 -04:00
NGnius (Graham)
4a9ceecc29 Improve dev info in README 2020-07-19 12:43:06 -04:00
16521ab7eb Remove initializer data once the block is placed 2020-07-19 01:42:32 +02:00
cc4ed3e174 Test fixes, block event Block property
Fixed Assert.Equal()
Changed tests to reflect changes
Added Block property to the block event args
Completely removed sync things
2020-07-19 01:13:39 +02:00
NGnius (Graham)
e0aa052305 Fix dev tools for preview changes 2020-07-16 20:38:51 -04:00
d842df7681 Implement init for position and rotation 2020-07-15 22:46:48 +02:00
3592c6f464 Add support for initializing blocks with properties
Newly created blocks use the initializer to set properties, allowing the user to set per-block properties
2020-07-15 21:58:24 +02:00
5bbb54c0c5 Automatically invoke the correct block constructor
And store delegates of dynamic methods invoking constructors
Tested with the automated tests
2020-07-13 21:55:48 +02:00
83 changed files with 5483 additions and 2714 deletions

View file

@ -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
View 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>

View file

@ -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

View file

@ -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));
}
}
}

View file

@ -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")]

View file

@ -0,0 +1,4 @@
<?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

View 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();
}

View file

@ -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

View 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;
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}
}

View file

@ -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

View file

@ -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
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}
}

View file

@ -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");
}
}

View file

@ -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>

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;

View 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 };
}
}

View file

@ -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,