using System; using System.Runtime.CompilerServices; using RobocraftX.Character; using RobocraftX.Character.Movement; using RobocraftX.Common.Players; using RobocraftX.Common.Input; using RobocraftX.CR.MachineEditing.BoxSelect; using RobocraftX.Physics; using RobocraftX.Blocks.Ghost; using Gamecraft.GUI.HUDFeedbackBlocks; using RobocraftX.Blocks; using RobocraftX.Multiplayer; using RobocraftX.PilotSeat; using Svelto.ECS; using Techblox.Camera; using Unity.Mathematics; using Svelto.ECS.DataStructures; using Svelto.ECS.EntityStructs; using Techblox.BuildingDrone; using TechbloxModdingAPI.Engines; using TechbloxModdingAPI.Utility; namespace TechbloxModdingAPI.Players { internal class PlayerEngine : IFunEngine { public string Name { get; } = "TechbloxModdingAPIPlayerGameEngine"; public EntitiesDB entitiesDB { set; private get; } public bool isRemovable => false; public IEntityFunctions Functions { get; set; } private bool isReady = false; public void Dispose() { isReady = false; } public void Ready() { isReady = true; } public uint GetLocalPlayer() { if (!isReady) return uint.MaxValue; var localPlayers = entitiesDB.QueryEntities(PlayersExclusiveGroups.LocalPlayers).ToBuffer(); if (localPlayers.count > 0) { return localPlayers.buffer[0].ID.entityID; } return uint.MaxValue; } public uint GetRemotePlayer() { if (!isReady) return uint.MaxValue; var localPlayers = entitiesDB.QueryEntities(PlayersExclusiveGroups.RemotePlayers).ToBuffer(); if (localPlayers.count > 0) { return localPlayers.buffer[0].ID.entityID; } return uint.MaxValue; } public long GetAllPlayerCount() { if (entitiesDB == null) return 0; long count = 0; foreach (ExclusiveGroupStruct eg in PlayersExclusiveGroups.AllPlayers) { count += entitiesDB.Count(eg); } return count; } public long GetLocalPlayerCount() { if (entitiesDB == null) return 0; return entitiesDB.Count(PlayersExclusiveGroups.LocalPlayers); } public long GetRemotePlayerCount() { if (entitiesDB == null) return 0; return entitiesDB.Count(PlayersExclusiveGroups.RemotePlayers); } public bool ExistsById(uint playerId) { if (entitiesDB == null) return false; return entitiesDB.Exists(playerId, PlayersExclusiveGroups.LocalPlayers) || entitiesDB.Exists(playerId, PlayersExclusiveGroups.RemotePlayers); } public bool SetLocation(uint playerId, float3 location, bool exitSeat = true) { if (entitiesDB == null) return false; var rbesOpt = GetCharacterStruct(playerId, out var group); if (!rbesOpt) return false; if (group == CharacterExclusiveGroups.InPilotSeatGroup && exitSeat) { ExitSeat(playerId); } rbesOpt.Get().position = location; return true; } public bool GetGameOverScreen(uint playerId) { if (entitiesDB == null) return false; ref HudActivatedBlocksEntityStruct habes = ref entitiesDB.QueryEntity(HUDFeedbackBlocksGUIExclusiveGroups.GameOverHudEgid); NativeDynamicArrayCast nativeDynamicArrayCast = new NativeDynamicArrayCast(habes.activatedBlocksOrdered); return nativeDynamicArrayCast.count > 0; } public bool IsDead(uint playerId) { if (entitiesDB == null) return true; return entitiesDB.Exists(playerId, CharacterExclusiveGroups.DeadCharacters); } // reusable methods [MethodImpl(MethodImplOptions.AggressiveInlining)] public OptionalRef GetCharacterStruct(uint playerId) where T : unmanaged, IEntityComponent => GetCharacterStruct(playerId, out _); [MethodImpl(MethodImplOptions.AggressiveInlining)] public OptionalRef GetCharacterStruct(uint playerId, out ExclusiveGroupStruct group) where T : unmanaged, IEntityComponent { group = default; if (GameState.IsBuildMode()) return entitiesDB.QueryEntityOptional(new EGID(playerId, LocalBuildingDrone.BuildGroup)); var characterGroups = CharacterExclusiveGroups.AllCharacters; for (int i = 0; i < characterGroups.count; i++) { EGID egid = new EGID(playerId, characterGroups[i]); var opt = entitiesDB.QueryEntityOptional(egid); if (opt.Exists) { group = characterGroups[i]; return opt; } } return new OptionalRef(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public OptionalRef GetPlayerStruct(uint playerId, PlayerType type) where T : unmanaged, IEntityComponent { var playerGroup = type == PlayerType.Local ? PlayersExclusiveGroups.LocalPlayers : PlayersExclusiveGroups.RemotePlayers; EGID egid = new EGID(playerId, playerGroup); return entitiesDB.QueryEntityOptional(egid); } public OptionalRef GetCameraStruct(uint playerId) where T : unmanaged, IEntityComponent { return entitiesDB.QueryEntityOptional(new EGID(playerId, CameraExclusiveGroups.PhysicCameraGroup)); } public EGID GetThingLookedAt(uint playerId, float maxDistance = -1f) { var opt = GetCameraStruct(playerId); if (!opt) return default; PhysicCameraRayCastEntityStruct rayCast = opt; float distance = maxDistance < 0 ? GhostBlockUtils.GetBuildInteractionDistance(entitiesDB, rayCast, GhostBlockUtils.GhostCastMethod.GhostCastProportionalToBlockSize) : maxDistance; if (rayCast.hit && rayCast.distance <= distance) return rayCast.hitEgid; //May be EGID.Empty (default) return default; } public unsafe Block[] GetSelectedBlocks(uint playerid) { if (!entitiesDB.Exists(playerid, BoxSelectExclusiveGroups.BoxSelectVolumeExclusiveGroup)) return Array.Empty(); var state = entitiesDB.QueryEntity(playerid, BoxSelectExclusiveGroups.BoxSelectVolumeExclusiveGroup); var blocks = entitiesDB.QueryEntity(playerid, BoxSelectExclusiveGroups.BoxSelectVolumeExclusiveGroup); if (!state.active) return Array.Empty(); var pointer = (EGID*) blocks.selectedBlocks.ToPointer(); var ret = new Block[blocks.count]; for (int j = 0; j < blocks.count; j++) { var egid = pointer[j]; ret[j] = Block.New(egid); } return ret; } public void EnterSeat(uint playerId, EGID seatId) { PilotSeatGroupUtils.SwapTagTo(Functions, seatId); var opt = GetCharacterStruct(playerId, out var group); if (!opt) return; ref CharacterPilotSeatEntityStruct charSeat = ref opt.Get(); var charId = new EGID(playerId, group); charSeat.pilotSeatEntity = entitiesDB.GetEntityReference(seatId); charSeat.entryPositionOffset = entitiesDB.QueryEntity(charId).position - entitiesDB.QueryEntity(seatId).position; ref var seat = ref entitiesDB.QueryEntity(seatId); seat.occupyingCharacter = entitiesDB.GetEntityReference(charId); charSeat.followCam = entitiesDB.QueryEntity(seatId).followCam; Functions.SwapEntityGroup(charId, CharacterExclusiveGroups.InPilotSeatGroup); } public void ExitSeat(uint playerId) { EGID egid = new EGID(playerId, CharacterExclusiveGroups.InPilotSeatGroup); var opt = entitiesDB.QueryEntityOptional(egid); if (!opt) return; opt.Get().instantExit = true; entitiesDB.PublishEntityChange(egid); } public uint GetPing() { return entitiesDB .QueryUniqueEntity(MultiplayerExclusiveGroups.MultiplayerStateGroup) .networkStats.PingMs; } } }