using System; using System.Linq; using GamecraftModdingAPI; using GamecraftModdingAPI.Commands; using GamecraftModdingAPI.Engines; using GamecraftModdingAPI.Players; using GamecraftModdingAPI.Utility; using HarmonyLib; using IllusionPlugin; using RobocraftX.Character.Weapons; using RobocraftX.Common.Players; using Svelto.ECS; using Svelto.ECS.Internal; using Unity.Mathematics; namespace BlockMod { public class BlockMod : IPlugin { public void OnApplicationStart() { Main.Init(); GameClient.SetDebugInfo("BlockModInfo", GetBlockInfo); Block[] blocks = new Block[0]; CommandBuilder.Builder("scaleBlocksRelative", "Scales the blocks you're looking at, relative to current size (current scale * new scale)." + " The block you're looking at stays where it is, everything else is moved next to it." + " The command remembers the cluster of blocks, use forgetBlocks to forget it.") .Action((scaleX, scaleY, scaleZ) => { var bl = new Player(PlayerType.Local).GetBlockLookedAt(); var cubes = GetCubes(ref blocks, bl); if (cubes == null) return; float3 reference = bl.Position; float3 scale = new float3(scaleX, scaleY, scaleZ); foreach (var block in cubes) { block.Scale *= scale; block.Position = reference + (block.Position - reference) * scale; } Logging.CommandLog("Blocks scaled."); }).Build(); CommandBuilder.Builder("scaleIndividually", "Scales the blocks you're looking at, but doesn't move them." + "The scale is relative, 1 means no change. Look at a block previously scaled to scale all of the blocks that were connected to it.") .Action((scaleX, scaleY, scaleZ) => { var cubes = GetCubesLookedAt(ref blocks); if (cubes == null) return; float3 scale = new float3(scaleX, scaleY, scaleZ); foreach (var block in cubes) block.Scale *= scale; }).Build(); CommandBuilder.Builder("moveBlocks", "Moves the blocks around.") .Action((x, y, z) => { var cubes = GetCubesLookedAt(ref blocks); if (cubes == null) return; foreach (var block in cubes) block.Position += new float3(x, y, z); }).Build(); CommandBuilder.Builder("forgetBlocks", "Forgets the cluster of blocks that we're changing.") .Action(() => blocks = new Block[0]).Build(); GameEngineManager.AddGameEngine(new Test()); } private class Test : IApiEngine { public void Ready() { try { CommandBuilder.Builder("weaponTest").Action(() => { var type = AccessTools.TypeByName("RobocraftX.Character.Weapons.CharacterEquippedWeaponStruct"); var dict = QueryEntitiesAndIndexInternal( new EGID(new Player(PlayerType.Local).Id, PlayersExclusiveGroups.LocalPlayers), out uint i, type); var dtype = typeof(ITypeSafeDictionary<>).MakeGenericType(type); var obj = Convert.ChangeType(dict, dtype); Array arr = (Array) AccessTools.PropertyGetter(dtype, "unsafeValues") .Invoke(obj, new object[0]); foreach (var element in arr) element.GetType().GetField("equippedWeaponType") .SetValue(element, WeaponType.PISTOL); }).Build(); } catch { // ignored } } private ITypeSafeDictionary QueryEntitiesAndIndexInternal(EGID entityGID, out uint index, Type type) { index = 0U; ITypeSafeDictionary typeSafeDictionary; if (!QueryEntityDictionary(entityGID.groupID, out typeSafeDictionary, type)) return null; return !typeSafeDictionary.TryFindIndex(entityGID.entityID, out index) ? null : typeSafeDictionary; } private bool QueryEntityDictionary( uint group, out ITypeSafeDictionary typeSafeDictionary, Type type) { object[] ps = {group, type, null}; bool ret = (bool) AccessTools.Method("Svelto.ECS.EntitiesDB:UnsafeQueryEntityDictionary") .Invoke(entitiesDB, ps); typeSafeDictionary = (ITypeSafeDictionary) ps[2]; return ret; } public EntitiesDB entitiesDB { get; set; } public void Dispose() { } public string Name { get; } = "TestEngine"; public bool isRemovable { get; } = true; } private string GetBlockInfo() { if (GameState.IsBuildMode()) { var block = new Player(PlayerType.Local).GetBlockLookedAt(); float3 pos = block.Position; float3 rot = block.Rotation; float3 scale = block.Scale; return $"Block: {block.Type} at {pos.x:F} {pos.y:F} {pos.z:F}\n" + $"- Rotation: {rot.x:F}° {rot.y:F}° {rot.z:F}°\n" + $"- Color: {block.Color.Color} darkness: {block.Color.Darkness}\n" + $"- Scale: {scale.x:F} {scale.y:F} {scale.z:F}\n" + $"- Label: {block.Label}"; } if (GameState.IsSimulationMode()) { var body = new Player(PlayerType.Local).GetSimBodyLookedAt(); float3 pos = body.Position; float3 rot = body.Rotation; float3 vel = body.Velocity; float3 ave = body.AngularVelocity; float3 com = body.CenterOfMass; return $"Body at {pos.x:F} {pos.y:F} {pos.z:F}\n" + $"- Rotation: {rot.x:F}° {rot.y:F}° {rot.z:F}°\n" + $"- Velocity: {vel.x:F} {vel.y:F} {vel.z:F}\n" + $"- Angular velocity: {ave.x:F} {ave.y:F} {ave.z:F}\n" + $"- {(body.Static ? "Static body" : $"Mass: {body.Mass:F} center: {com.x:F} {com.y:F} {com.z:F}")}"; } return "Switching modes..."; } private bool SameCluster(Block[] bs, Block block) { var id = block.Id; return bs.Any(b => b.Id == id); } private Block[] GetCubes(ref Block[] bs, Block block) => SameCluster(bs, block) ? bs : bs = block.GetConnectedCubes(); private Block[] GetCubesLookedAt(ref Block[] bs) { var bl = new Player(PlayerType.Local).GetBlockLookedAt(); if (bl == null) return null; var cubes = GetCubes(ref bs, bl); return cubes; } public void OnApplicationQuit() { } public void OnLevelWasLoaded(int level) { } public void OnLevelWasInitialized(int level) { } public void OnUpdate() { } public void OnFixedUpdate() { } public string Name { get; } = "BlockMod"; public string Version { get; } = "v1.0.0"; } }