Welcome to Keen Software House Forums! Log in or Sign up to interact with the KSH community.
  1. You are currently browsing our forum as a guest. Create your own forum account to access all forum functionality.

Leaving Sensors and Cockpits [Edit: WAD]

Discussion in 'Questions and Suggestions' started by Michael Viktor Starberg, Jul 30, 2017.

Thread Status:
This last post in this thread was made more than 31 days old.
  1. Michael Viktor Starberg Trainee Engineer

    Messages:
    18
    Hello.

    I am having fun with sensors and a programmable block but run into a problem.
    My idea was to sense when I approach my ship (welcome) and when I leave (goodbye) that currently just switch a timer on/off. No need to have that ticking if I am not even close.

    The possibilities here are endless. Imagine a fighter that deployes weapons and go dark when a frriendly close to it. Ans shuts itself down when you park it. Would look pretty cool.

    So for so good. The crux is that a sensor registers a player as leaving the sensor as soon as you get into a cockpit. I can understand that the sensor no longer think I am a player but a ship. This kinda ruin my whole idea.

    So I was hoping that you could re-visit the design for sensors and maybe change its behaviour so it still recognize a player inside a cockpit within its range as being in range.
     
  2. Pluttrik Trainee Engineer

    Messages:
    11
    A clunky way of doing it could be if the player is close to the ship and dissapears he is probably inside the ship (use the position from MyDetectedEntityInfo and calculate the position between them). Not sure if changing the sensor to recognize if someone is in cockpit is good idea since sensors job is just to detect if something is there, but its still a tempting one.
     
  3. Michael Viktor Starberg Trainee Engineer

    Messages:
    18
    Very smart workaround Pluttrik. But as you described it; clunky. That's a lot of C# that would require the serialization of Storage in ways I don't even wanna think about. One player offline sure; but there could be several players in multiplayer. Aj! That surely must be done in the core game and not half-baked using scripting.

    I have been thinking. It is too late to change sensor behaviour. Maybe there are sensors, timers and scripts out there that depends on that players disapears when entering a cockpit. We don't know.

    So instead of over-anylizing what impact my change request would cause; I would ask for an addition instead. Adding is easier than changing.

    My hope is that the sensor gets a new checkbox:
    [ ] Detect players in cockpit/control stations

    As the default is false, it is backward compatible with what the community have engineered so far. We get to eat the cake and have it too.

    Still. This surely must be a low priority request. Perhaps after release as it would allow for some very cool builds.

    As for Beta; I hope the developers call Sensors 'working-as-designed' and move on to the Remote Control. It is currently completely broken and I rather see auto piloting work. (Hint: The game will need to have direction in all three angels in GPS to ever make us engineers trust using the darn thing without heavy duty see sharpening)

    Would also like to add that the game is rich enough so that if some aspect of the game is a bit flaky, there is plenty to do elsewhere. You just park your pet-project and move on to the next thing. Not many games have that going for it! :)
     
    Last edited: Aug 9, 2017
  4. Forcedminer Senior Engineer

    Messages:
    2,227
    yes i have also noticed this.
    this is my example

    i rigged a sensor block to detect owner 20 meters in all directions or so
    timer1 . turn off beacon. play a sound block if player is close
    timer 2. turn on beacon play a sound block if player is away

    for when i fly a distance away it makes a beeping sound and turns the beacon on so i can find it easier
    when i fly close it turns it off and makes the sound

    when i enter the cockpit it thinks im a distance away and turns on the beacon
     
  5. Michael Viktor Starberg Trainee Engineer

    Messages:
    18
    Yeah Forceminer. Glad I am not alone to discover this.

    As I said, adding that checkbox would make for awesome builds. But I also suspect it would require some major surguery to the core game. No Thanks. Not in Beta.
     
  6. Georgik Apprentice Engineer

    Messages:
    215
    If you can use C# a little, there is no need for computing if player "disappeared" from sensor area, just check for IMyShipController.IsUnderControl (means player is sitting in it).
    Something like:
    Code:
    bool detected = false;
    void Main(string argument) {
    	var sensor = GridTerminalSystem.GetBlockWithName("Sensor") as IMySensorBlock;
    	var cockpit = GridTerminalSystem.GetBlockWithName("Cockpit") as IMyShipController;
    	var timerOn = GridTerminalSystem.GetBlockWithName("Timer Block Sensor ON") as IMyTimerBlock;
    	var timerOff = GridTerminalSystem.GetBlockWithName("Timer Block Sensor OFF") as IMyTimerBlock;
    
    	if (sensor == null) return;
    
    	var tmp = false;
    	if (cockpit == null) tmp = sensor.IsActive; // is something being detected right now
    	else tmp = (sensor.IsActive || cockpit.IsUnderControl);
    
    	if (tmp && !detected) {
    		if (timerOn != null) timerOn.Trigger();
    		detected = true;
    	} else if (!tmp && detected) {
    		if (timerOff != null) timerOff.Trigger();
    		detected = false;
    	}
    }
     
    • Agree Agree x 2
  7. Michael Viktor Starberg Trainee Engineer

    Messages:
    18
    Georgik! Thanks! I can use C# a lot! Busy today but you just saved my friday evening. I'll try it and post whatever solution I can come up with. But just by eyeballing the code above makes me sure that it will work. It's still a workaround so my humble request still stands. But again; thanks!

    (Also, let me guess. You stem from C, Javascript, Java and maybe Typescript?)
     
    Last edited: Aug 10, 2017
  8. Georgik Apprentice Engineer

    Messages:
    215
    Well, actually from nothing :D
    Learned the magic of scripts in Arma, then a little of Python at school, C# in SE & minimum of Java in Android.
    I'm not aimed on any of these, everything seems the same for me.
     
  9. Michael Viktor Starberg Trainee Engineer

    Messages:
    18
    I am an Anders Hejlsberg stalker. Turbo Pascal, Turbo C, Borland C++, Object Pascal, Borland Delphi, Borland J++, Visual C++, C#, TypeScript. Hmm. I see a pattern here. I don't get to code much today, so when I found the Programmable Block and saw it was using C# I just smiled :)

    (and we are somewhat off-topic)
     
    Last edited: Aug 10, 2017
  10. Michael Viktor Starberg Trainee Engineer

    Messages:
    18
    Here is the entire script. Sharing is caring... And maybe a moderator can move this thread to the coding section of the forum, as this thread is no longer a suggestion nor a feature request.

    Code:
    
            List<DesiredItem> desiredItems;
            Dictionary<string, DesiredItem> desiredItemsLookup;
    
            IMyShipController cockpit;
            IMyShipConnector connector;
            IMyInventory inventoryGeneric;
            IMyInventory inventorySpecific;
            IMyTextPanel panel;
            IMyTimerBlock timer;
    
            public Program()
            {
                desiredItems = new List<DesiredItem>
                {
                    new DesiredItem { Name = "SteelPlate", Caption = "Steel plate", DesiredAmount = 15000, Type = CargoType.Generic },
                    new DesiredItem { Name = "Construction", Caption = "Construction c", DesiredAmount = 7500, Type = CargoType.Generic },
                    new DesiredItem { Name = "InteriorPlate", Caption = "Interior plate", DesiredAmount = 7500, Type = CargoType.Generic },
                    new DesiredItem { Name = "LargeTube", Caption = "Large tubes", DesiredAmount = 750, Type = CargoType.Generic },
                    new DesiredItem { Name = "Computer", Caption = "Computers", DesiredAmount = 2000 },
                    new DesiredItem { Name = "Motor", Caption = "Motors", DesiredAmount = 2000 },
                    new DesiredItem { Name = "Display", Caption = "Displays", DesiredAmount = 2000 },
                    new DesiredItem { Name = "MetalGrid", Caption = "Metal grid", DesiredAmount = 1500 },
                    new DesiredItem { Name = "SmallTube", Caption = "Small tubes", DesiredAmount = 1500 },
                    new DesiredItem { Name = "Thrust", Caption = "Thrusters c", DesiredAmount = 1500 },
                    new DesiredItem { Name = "PowerCell", Caption = "Power cells", DesiredAmount = 500 },
                    new DesiredItem { Name = "Reactor", Caption = "Reactor c", DesiredAmount = 200 },
                    new DesiredItem { Name = "BulletproofGlass", Caption = "Bullet glass", DesiredAmount = 200 },
                    new DesiredItem { Name = "Medical", Caption = "Medical c", DesiredAmount = 200 },
                    new DesiredItem { Name = "RadioCommunication", Caption = "Radio c", DesiredAmount = 200 },
                    new DesiredItem { Name = "Detector", Caption = "Detectors", DesiredAmount = 200 },
                };
    
                desiredItemsLookup = desiredItems.ToDictionary(k => k.Name, v => v);
    
                cockpit = (IMyShipController)GridTerminalSystem.GetBlockWithName("Weld Cockpit");
                connector = (IMyShipConnector)GridTerminalSystem.GetBlockWithName("Weld Connector Back");
                inventoryGeneric = (IMyInventory)GridTerminalSystem.GetBlockWithName("Weld Cargo Generic").GetInventory(0);
                inventorySpecific = (IMyInventory)GridTerminalSystem.GetBlockWithName("Weld Cargo Specific").GetInventory(0);
                panel = (IMyTextPanel)GridTerminalSystem.GetBlockWithName("Weld Text panel");
                timer = (IMyTimerBlock)GridTerminalSystem.GetBlockWithName("Weld Timer Block");
    
            }
    
            public void Main(string args)
    		{
                switch(args)
                {
                    case "stats":
                        Stats();
                        break;
                    case "refill":
                        Refill();
                        break;
                    case "sensorEnter":
                        SensorEnter();
                        break;
                    case "sensorLeave":
                        SensorLeave();
                        break;
                    default:
                        Echo("No command given");
                        break;
                }
    		}
    
            private void Stats()
            {
                ClearTextPanel();
    
                var list = new List<ReesolvedItem>(32);
                var handled = new HashSet<string>();
                foreach(var desiredItem in desiredItems)
                {
                    handled.Add(desiredItem.Name);
                }
    
                var inventoryItems = GetInventoryItems();
             
                foreach(var item in inventoryItems)
                {
                    var name = item.Content.SubtypeName;
                    var resolvedItem = new ReesolvedItem
                    {
                        Name = name,
                        Caption = $"[{name}]",
                        DesiredAmount = -1,
                        CurrentAmount = (double)item.Amount,
                        Percentage = double.PositiveInfinity
                    };
    
                    var desiredItem = default(DesiredItem);
                    if (desiredItemsLookup.TryGetValue(name, out desiredItem))
                    {
                        resolvedItem.Caption = desiredItem.Caption;
                        resolvedItem.DesiredAmount = desiredItem.DesiredAmount;
                    }
    
                    if (resolvedItem.DesiredAmount > 0)
                    {
                        resolvedItem.Percentage = resolvedItem.CurrentAmount / resolvedItem.DesiredAmount * 100;                  
                    }
    
                    list.Add(resolvedItem);
                    handled.Remove(resolvedItem.Name);
                }
    
                foreach(var unhandled in handled)
                {
                    var desiredItem = default(DesiredItem);
                    if (desiredItemsLookup.TryGetValue(unhandled, out desiredItem))
                    {
                        var resolvedItem = new ReesolvedItem
                        {
                            Name = desiredItem.Name,
                            Caption = desiredItem.Caption,
                            DesiredAmount = -1,
                            CurrentAmount = 0,
                            Percentage = 0
                        };
    
                        list.Add(resolvedItem);
                    }
                }
    
    
                list = list.OrderBy(s => Math.Truncate(s.Percentage)).ThenByDescending(s => s.CurrentAmount).ThenBy(s => s.Caption).ToList();
    
                foreach(var summary in list)
                {
                    var percent = (summary.Percentage != double.PositiveInfinity) ? $"{summary.Percentage:N1}%" : "N/A";
                    var amount = summary.CurrentAmount;
                    WriteLineToTextPanel($" {summary.Caption,-16}{amount,6:N0} {percent,7}");
                }
            }
    
            private void Refill()
            {
                if (connector.Status != MyShipConnectorStatus.Connected) return;
                var primaryBlock = GridTerminalSystem.GetBlockWithName("Base Cargo Components Primary");
                if (primaryBlock == null) return;
    
                var primaryInventory = primaryBlock.GetInventory(0);
                var primaryInventoryItems = primaryInventory.GetItems();
    
                var inventoryItems = GetInventoryItems();
    
                foreach (var desiredItem in desiredItems)
                {
                    if (desiredItem.DesiredAmount > 0)
                    {
                        primaryInventoryItems = primaryInventory.GetItems();
    
                        for (int primaryIndex = primaryInventoryItems.Count-1; primaryIndex >= 0; primaryIndex--)
                        {
                            var item = primaryInventoryItems[primaryIndex];
                            if (desiredItem.Name == item.Content.SubtypeName)
                            {
                                var inventoryItem = inventoryItems.SingleOrDefault(i => i.Content.SubtypeName == desiredItem.Name);
    
                                var currentAmount = (double)(inventoryItem?.Amount ?? 0);
                                var desiredAmount = desiredItem.DesiredAmount - currentAmount;
                                var primaryAmount = (double)item.Amount;
                                if (desiredAmount > primaryAmount)
                                {
                                    desiredAmount = primaryAmount;
                                }
    
                                var inventory = desiredItem.Type == CargoType.Generic ? inventoryGeneric : inventorySpecific;
                                primaryInventory.TransferItemTo(inventory, primaryIndex, stackIfPossible: true, amount: (VRage.MyFixedPoint)Math.Truncate(desiredAmount));
    
                                break;
                            }
                        }
                    }
                }
            }
    
    
            private void SensorLeave()
            {
                // We start by checking if engineer went into cockpit and if connected to a base
                var underControl = cockpit.IsUnderControl;
                var connected = connector.Status == MyShipConnectorStatus.Connected;
    
                if (underControl)
                {
                    // Engineer just went into cockpit
                    panel.WritePublicText("Welcome onboard engineer");
                    timer.ApplyAction("OnOff_On");
                    timer.ApplyAction("Start");
                    if (connected)
                    {
                        // As I tend to forget to fill up my welder with all the good stuff, let's do that.
                        Refill();
                    }
                }
                else
                {
                    // Engineer have left cockpit. No need to have that timer running every second.
                    timer.ApplyAction("OnOff_Off");
                    panel.WritePublicText("");
                }
            }
    
            private void SensorEnter()
            {
                // No need to do anything for entering the sensor. Except for the welder.
                // I can't count how many times I've welded myself to death by forgetting to turn those darn things off.
                // I'm less suicidal now :)
                TurnThoseFrekkinDangerousWeldersOffThankYouVeryMuch();
            }
    
            private IEnumerable<IMyInventoryItem> GetInventoryItems()
            {
                var inventories = inventoryGeneric.GetItems().Concat(inventorySpecific.GetItems());
                return inventories;
            }
    
            private void TurnThoseFrekkinDangerousWeldersOffThankYouVeryMuch()
            {
                var welders = new List<IMyShipWelder>();
    
                GridTerminalSystem.GetBlockGroupWithName("Weld Welders").GetBlocksOfType<IMyShipWelder>(welders);
                foreach (var welder in welders)
                {
                    welder.ApplyAction("OnOff_Off");
                }
            }
    
    
            private void ClearTextPanel() => panel.WritePublicText("", false);
            private void WriteLineToTextPanel(string text) => panel.WritePublicText(text + "\n", true);
    
    
            class DesiredItem
            {
                public string Name { get; set; }
                public string Caption { get; set; }
                public double DesiredAmount { get; set; }
                public CargoType Type { get; set; }
            }
    
            class ReesolvedItem
            {
                public string Name { get; set; }
                public string Caption { get; set; }
                public double DesiredAmount { get; set; }
                public double CurrentAmount { get; set; }
                public double Percentage { get; set; }
            }
    
            enum CargoType
            {
                Specific = 0,
                Generic = 1
            }
    
    
    
     
    Last edited: Aug 24, 2017
Thread Status:
This last post in this thread was made more than 31 days old.