1. This forum is obsolete and read-only. Feel free to contact us at support.keenswh.com

Fully automatic doors

Discussion in 'Programming Released Codes' started by Pluttrik, Aug 8, 2018.

Thread Status:
This last post in this thread was made more than 31 days old.
  1. Pluttrik

    Pluttrik Trainee Engineer

    Messages:
    11
    I do not know if anyone out there already made this, but all i could see was "timed door" this "timed door" that.
    This script makes it possible to have fully automatic doors, which opens when the player is close enough using only one sensor on mutiple doors (63 999 doors to be exact).

    My first thought to make this script was by using rectangles as a sensor for every door and when the player is inside the rectangle the door will open. Though this is very dynamic and straight forward, but it had to be recalculated every time. Which will be kinda heavy since its vector calculations.
    I then stumbled across grid coordinates, which are static. By using these grid coordinates I could place out "trigger points" for every door. And when a player is on a trigger point, the door will open. This is a one time calculation only for placing the trigger points, and every update I will just check where the player are in terms of grid coordinates.

    Here's the workshop for the script:
    https://steamcommunity.com/sharedfiles/filedetails/?id=1470507447

    And here's the script in plain text:
    Code:
    const string SENSOR_NAME_PREFIX = "door"; // CASE INSENSITIVE
    const string AUTOMATIC_DOOR_NAME_PREFIX = "autoamtic"; // CASE INSENSITIVE
    
    HashSet<AutoDoor> ActiveDoors = new HashSet<AutoDoor>();
    Dictionary<Vector3I, List<int>> TriggerPoints = new Dictionary<Vector3I, List<int>>();
    List<AutoDoor> AutoDoors = new List<AutoDoor>();
    List<IMySensorBlock> Sensors = new List<IMySensorBlock>();
    
    class AutoDoor {
    
    	private IMyDoor door;
    	private List<Vector3I> triggerPoints = new List<Vector3I>();
    	private bool semi;
    
    	public bool Semi {
    		get {
    			return semi;
    		}
    	}
    
    	public List<Vector3I> TriggerPoints {
    		get {
    			return triggerPoints;
    		}
    	}
    
    	public DoorStatus Status {
    		get {
    			return door.Status;
    		}
    	}
    
    	public AutoDoor(IMyDoor door) {
    		this.door = door;
    		this.semi = IsSemiAutomatic();
    		triggerPoints.Add(door.Position);
    		Vector3 direction = door.WorldMatrix.Forward * 2.5f;
    		triggerPoints.Add(door.CubeGrid.WorldToGridInteger(door.GetPosition() + direction));
    		if (!(door is IMyAirtightSlideDoor))
    			triggerPoints.Add(door.CubeGrid.WorldToGridInteger(door.GetPosition() - direction));
    	}
    
    	private bool IsSemiAutomatic() {
    		if (this.door.CustomData == "semi")
    			return true;
    		return false;
    	}
    
    	public bool IsPlayerOnTriggerPoint(Vector3I position) {
    		if (this.triggerPoints.Contains(position))
    			return true;
    		return false;
    	}
    
    	public bool IsAnyPlayerOnTriggerPoint(List<Vector3I> positions) {
    		foreach (Vector3I position in positions) {
    			if (IsPlayerOnTriggerPoint(position))
    				return true;
    		}
    		return false;
    	}
    
    	public bool IsInsideSensorFields(List<BoundingBoxI> fields) {
    		foreach (BoundingBoxI field in fields) {
    			foreach (Vector3I point in this.triggerPoints) {
    				ContainmentType containmentType = field.Contains(point);
    				if (containmentType == ContainmentType.Disjoint)
    					return false;
    			}
    		}
    		return true;
    	}
    
    	public void Open() {
    		door.OpenDoor();
    	}
    
    	public void Close() {
    		door.CloseDoor();
    	}
    }
    
    public Program() {
    	Initialize();
    	Runtime.UpdateFrequency = UpdateFrequency.Update10;	
    }
    
    bool IsAutomaticDoor(IMyDoor door) {
    	if (door.CustomName.ToLower().StartsWith(AUTOMATIC_DOOR_NAME_PREFIX) && !(door is IMyAirtightHangarDoor))
    		return true;
    	return false;
    }
    
    void AddDoorTriggerPoints(Dictionary<Vector3I, List<int>> triggerPoints, List<Vector3I> points, int doorIndex) {
    	foreach (Vector3I point in points) {
    		List<int> doorIndexes;
    		if (!TriggerPoints.TryGetValue(point, out doorIndexes)) {
    			doorIndexes = new List<int>();
    			triggerPoints.Add(point, doorIndexes);
    		}
    		doorIndexes.Add(doorIndex);
    	}
    }
    
    List<BoundingBoxI> GetSensorFields(List<IMySensorBlock> sensors) {
    	List<BoundingBoxI> fields = new List<BoundingBoxI>();
    	foreach (IMySensorBlock sensor in sensors) {
    		Vector3I forward = (sensor.CubeGrid.WorldToGridInteger(sensor.GetPosition() + (sensor.WorldMatrix.Forward * 2.5)) - sensor.Position);
    		Vector3 frontExtend = (new Vector3(sensor.FrontExtend - 1.25f)) * forward;
    		Vector3 backExtend = (new Vector3(sensor.BackExtend + 1.25f)) * -forward;
    
    		Vector3I right = (sensor.CubeGrid.WorldToGridInteger(sensor.GetPosition() + (sensor.WorldMatrix.Right * 2.5)) - sensor.Position);
    		Vector3 rightExtend = (new Vector3(sensor.RightExtend)) * right;
    		Vector3 leftExtend = (new Vector3(sensor.LeftExtend)) * -right;
    
    		Vector3I top = (sensor.CubeGrid.WorldToGridInteger(sensor.GetPosition() + (sensor.WorldMatrix.Up * 2.5)) - sensor.Position);
    		Vector3 topExtend = (new Vector3(sensor.TopExtend)) * top;
    		Vector3 bottomExtend = (new Vector3(sensor.BottomExtend)) * -top;
    
    		Vector3 edge1 = sensor.Position + (frontExtend + rightExtend + topExtend) / 2.5f;
    		Vector3 edge2 = sensor.Position + (backExtend + leftExtend + bottomExtend) / 2.5f;
    		BoundingBoxI field = new BoundingBoxI((Vector3I)Vector3.Min(edge1, edge2), (Vector3I)Vector3.Max(edge1, edge2));
    		fields.Add(field);
    	}
    	return fields;
    }
    
    void Initialize() {
    	ActiveDoors.Clear();
    	AutoDoors.Clear();
    	Sensors.Clear();
    
    	List<IMyDoor> autoDoors = new List<IMyDoor>();
    	GridTerminalSystem.GetBlocksOfType<IMyDoor>(autoDoors, door => IsAutomaticDoor(door));
    	GridTerminalSystem.GetBlocksOfType<IMySensorBlock>(Sensors, sensor => sensor.CustomName.ToLower().StartsWith(SENSOR_NAME_PREFIX));
    	List<BoundingBoxI> sensorFields = GetSensorFields(Sensors);
    	for (int i = 0; i < autoDoors.Count; i++) {
    		IMyDoor door = autoDoors[i];
    		door.CloseDoor();
    		AutoDoor autoDoor = new AutoDoor(door);
    
    		// Only add doors which is inside the sensor fields
    		if (autoDoor.IsInsideSensorFields(sensorFields)) {
    			AutoDoors.Add(autoDoor);
    			AddDoorTriggerPoints(TriggerPoints, autoDoor.TriggerPoints, i);
    		}
    	}
    }
    
    void OpenDoorsAtPoint(Dictionary<Vector3I, List<int>> triggerPoints, List<AutoDoor> doors, Vector3I point) {
    	List<AutoDoor> triggeredDoors = new List<AutoDoor>();
    	List<int> doorIndexes = new List<int>();
    	if (triggerPoints.TryGetValue(point, out doorIndexes)) {
    		foreach (int index in doorIndexes) {
    			AutoDoor autoDoor = doors[index];
    			ActiveDoors.Add(autoDoor);
    			if (!autoDoor.Semi)
    				autoDoor.Open();
    		}
    	}
    }
    
    public void Main(string argument, UpdateType updateType) {
    	//Echo(Runtime.LastRunTimeMs.ToString());
    	switch (argument.ToLower()) {
    		case "refresh":
    			Initialize();
    			break;
    		case "enable":
    			Runtime.UpdateFrequency = UpdateFrequency.Update10;
    			break;
    		case "disable":
    			Runtime.UpdateFrequency = UpdateFrequency.None;
    			break;
    		default:
    			var players = new List<MyDetectedEntityInfo>();
    			var playerGridPositions = new List<Vector3I>();
    			Sensors.ForEach(sensor => sensor.DetectedEntities(players));
    
    			// Halt the script while no one is there
    			if (players.Count == 0)
    				Runtime.UpdateFrequency = UpdateFrequency.None;
    
    			foreach (var player in players) {
    				Vector3I playerGridPosition = Me.CubeGrid.WorldToGridInteger(player.Position);
    				playerGridPositions.Add(playerGridPosition);
    				OpenDoorsAtPoint(TriggerPoints, AutoDoors, playerGridPosition);
    			}
    			ActiveDoors.RemoveWhere(delegate(AutoDoor door) {
    				if (!door.IsAnyPlayerOnTriggerPoint(playerGridPositions)) {
    					door.Close();
    					return true;
    				}
    				return false;
    			});
    			break;
    	}
    }
    Would like to hear some feedback and ideas from you guys.
     
Thread Status:
This last post in this thread was made more than 31 days old.