Skip to content

Instantly share code, notes, and snippets.

@spectras
Created May 22, 2020 16:09
Show Gist options
  • Save spectras/2527493bcd32dc66eb52fab500e1d7c8 to your computer and use it in GitHub Desktop.
Save spectras/2527493bcd32dc66eb52fab500e1d7c8 to your computer and use it in GitHub Desktop.
using Sandbox.Game.EntityComponents;
using Sandbox.ModAPI.Ingame;
using Sandbox.ModAPI.Interfaces;
using SpaceEngineers.Game.ModAPI.Ingame;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System;
using VRage.Collections;
using VRage.Game.Components;
using VRage.Game.GUI.TextPanel;
using VRage.Game.ModAPI.Ingame.Utilities;
using VRage.Game.ModAPI.Ingame;
using VRage.Game.ObjectBuilders.Definitions;
using VRage.Game;
using VRage;
using VRageMath;
using Sandbox.Game.Screens.Helpers;
using EmptyKeys.UserInterface.Generated.EditFactionIconView_Bindings;
using System.Xml;
namespace IngameScript
{
partial class Program
{
public partial class RecycleRange : ISubProgram
{
List<IMySensorBlock> ShipSensors;
List<IMyMotorStator> Doors;
List<IMyLightingBlock> DoorLights;
List<IMyShipGrinder> Grinders;
// List<IMyTerminalBlock> Containers;
// IMyTextSurface Display;
// List<IMyFunctionalBlock> ActivityIndicators;
// List<IMyFunctionalBlock> ErrorIndicators;
// List<IMyFunctionalBlock> WorkingIndicators;
public readonly string SectionName;
public ITextStream Logger;
public UpdateFrequency UpdateFrequency { get; private set; }
State CurrentState;
public RecycleRange(string sectionName, ITextStream logger)
{
ShipSensors = new List<IMySensorBlock>();
// Containers = new List<IMyTerminalBlock>();
Doors = new List<IMyMotorStator>();
DoorLights = new List<IMyLightingBlock>();
Grinders = new List<IMyShipGrinder>();
SectionName = sectionName;
Logger = logger;
CurrentState = null;
UpdateFrequency = UpdateFrequency.None;
}
public void Rescan(IMyGridTerminalSystem grid, IMyTerminalBlock me)
{
Logger.Write("Rescanning...\n");
Func<IMyTerminalBlock, bool> onMyGrid = (block => block.IsSameConstructAs(me));
util.GetBlocksWithSection<IMySensorBlock>(grid, SectionName, ShipSensors, onMyGrid);
util.GetBlocksWithSection<IMyMotorStator>(grid, SectionName, Doors, block => onMyGrid(block) && block.Torque > 0.0);
util.GetBlocksWithSection<IMyLightingBlock>(grid, SectionName, DoorLights, onMyGrid);
grid.GetBlocksOfType<IMyShipGrinder>(Grinders, onMyGrid);
foreach (var sensor in ShipSensors) { Logger.Write($"ShipSensor: {sensor.CustomName}\n"); }
foreach (var door in Doors) { Logger.Write($"Door: {door.CustomName}\n"); }
foreach (var light in DoorLights) { Logger.Write($"DoorLight: {light.CustomName}\n"); }
Logger.Write($"Found {Grinders.Count} grinders\n");
}
public void Reset()
{
if (CurrentState != null) { CurrentState.Leave(this); }
CurrentState = new IdleState();
CurrentState.Enter(this);
Logger.Write("Reset to idle state\n");
}
public void Main(string argument, UpdateType source)
{
State newState = null;
if ((source & UpdateType.Terminal) != 0 || (source & UpdateType.Trigger) != 0) {
newState = CurrentState.OnCommand(this, argument);
}
if ((source & UpdateType.Update100) != 0) {
newState = CurrentState.OnUpdate(this, source);
}
if (newState != CurrentState) {
Logger.Write($"Switching to {newState}\n");
CurrentState.Leave(this);
newState.Enter(this);
CurrentState = newState;
}
}
void StartDoors()
{
foreach (var door in Doors) {
door.TargetVelocityRPM = -door.TargetVelocityRPM;
door.RotorLock = false;
door.Enabled = true;
}
foreach (var light in DoorLights) {
light.BlinkIntervalSeconds = 2.0f; // todo make it configurable
light.BlinkLength = 20.0f; // allow color change too
}
}
void StopDoors()
{
foreach (var door in Doors) {
door.RotorLock = true;
door.Enabled = false;
}
foreach (var light in DoorLights) {
light.BlinkIntervalSeconds = 0.0f; // todo color change too
}
}
}
}
}
using Sandbox.Game.EntityComponents;
using Sandbox.ModAPI.Ingame;
using Sandbox.ModAPI.Interfaces;
using SpaceEngineers.Game.ModAPI.Ingame;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System;
using VRage.Collections;
using VRage.Game.Components;
using VRage.Game.GUI.TextPanel;
using VRage.Game.ModAPI.Ingame.Utilities;
using VRage.Game.ModAPI.Ingame;
using VRage.Game.ObjectBuilders.Definitions;
using VRage.Game;
using VRage;
using VRageMath;
namespace IngameScript
{
partial class Program
{
public partial class RecycleRange
{
private const int ImmobilityCycles = 10;
private const float DoorEpsilon = 0.00628f;
abstract class State
{
public virtual void Enter(RecycleRange station) { }
public virtual void Leave(RecycleRange station) { }
public virtual State OnCommand(RecycleRange station, string argument) { return this; }
public virtual State OnUpdate(RecycleRange station, UpdateType source) { return this; }
}
class IdleState : State
{
public override void Enter(RecycleRange station)
{
//TODO turn lights off
foreach (var sensor in station.ShipSensors) {
sensor.DetectPlayers = false;
sensor.DetectFloatingObjects = false;
sensor.DetectSmallShips = true;
sensor.DetectLargeShips = true;
sensor.DetectStations = false;
sensor.DetectSubgrids = false;
sensor.DetectAsteroids = false;
sensor.DetectOwner = true;
sensor.DetectFriendly = true;
sensor.DetectNeutral = true;
sensor.DetectEnemy = true;
sensor.Enabled = true;
}
}
public override void Leave(RecycleRange station)
{
foreach (var sensor in station.ShipSensors) { sensor.Enabled = false; }
}
public override State OnCommand(RecycleRange station, string argument)
{
if (argument == "load") { return new LoadingState(); }
return this;
}
}
class LoadingState : State
{
public override void Enter(RecycleRange station)
{
//TODO turn lights on
}
public override State OnCommand(RecycleRange station, string argument)
{
if (argument == "start") { return new LockingState(); }
return this;
}
}
class LockingState : State
{
public override void Enter(RecycleRange station)
{
station.StartDoors();
station.UpdateFrequency = UpdateFrequency.Update100;
}
public override void Leave(RecycleRange station)
{
station.StopDoors();
station.UpdateFrequency = UpdateFrequency.None;
}
public override State OnUpdate(RecycleRange station, UpdateType source)
{
var inProgress = station.Doors.Exists(door => {
var angle = door.Angle;
return door.LowerLimitRad + DoorEpsilon < angle
&& angle < door.UpperLimitRad - DoorEpsilon;
});
if (!inProgress) { return new ProcessingState(); }
return this;
}
public override State OnCommand(RecycleRange station, string argument)
{
if (argument == "stop") { return new UnlockingState(); }
return this;
}
}
class ProcessingState : State
{
class EntityInfo
{
public Vector3D Position;
public int ChangeCycle;
}
private Dictionary<long, EntityInfo> Entities;
private int Cycle;
private List<MyDetectedEntityInfo> DetectedEntities; // cached to avoid allocating on all updates
public ProcessingState()
{
Entities = new Dictionary<long, EntityInfo>();
Cycle = 0;
DetectedEntities = new List<MyDetectedEntityInfo>();
}
public override void Enter(RecycleRange station)
{
foreach (var sensor in station.ShipSensors) { sensor.Enabled = true; }
foreach (var grinder in station.Grinders) {
grinder.UseConveyorSystem = true;
grinder.Enabled = true;
}
station.UpdateFrequency = UpdateFrequency.Update100;
}
public override void Leave(RecycleRange station)
{
foreach (var sensor in station.ShipSensors) { sensor.Enabled = false; }
foreach (var grinder in station.Grinders) { grinder.Enabled = false; }
station.UpdateFrequency = UpdateFrequency.None;
}
public override State OnCommand(RecycleRange station, string argument)
{
if (argument == "pause") { return new PausedState(); }
if (argument == "stop") { return new UnlockingState(); }
return this;
}
public override State OnUpdate(RecycleRange station, UpdateType source)
{
EntityInfo info;
Cycle += 1;
int lastMoveCycle = 0;
foreach (var sensor in station.ShipSensors) {
sensor.DetectedEntities(DetectedEntities);
foreach (var entity in DetectedEntities) {
var position = entity.BoundingBox.Center;
if (!Entities.TryGetValue(entity.EntityId, out info)) {
info = new EntityInfo() {
Position = position,
ChangeCycle = Cycle
};
station.Logger.Write($"Added entity {entity.EntityId}\n");
Entities.Add(entity.EntityId, info);
lastMoveCycle = Cycle;
} else {
if (info.Position.Equals(position, 0.01)) {
lastMoveCycle = Math.Max(lastMoveCycle, info.ChangeCycle);
} else {
station.Logger.Write($"Live entity {entity.EntityId}\n");
info.Position = position;
info.ChangeCycle = Cycle;
lastMoveCycle = Cycle;
}
}
}
DetectedEntities.Clear();
}
station.Logger.Write($"Cycle: {Cycle}, last move: {lastMoveCycle}\n");
if (Cycle > lastMoveCycle + ImmobilityCycles) { return new UnlockingState(); }
return this;
}
}
class PausedState : State
{
public override State OnCommand(RecycleRange station, string argument)
{
if (argument == "start") { return new ProcessingState(); }
if (argument == "stop") { return new UnlockingState(); }
return this;
}
}
class UnlockingState : State
{
public override void Enter(RecycleRange station)
{
station.StartDoors();
station.UpdateFrequency = UpdateFrequency.Update100;
}
public override void Leave(RecycleRange station)
{
station.StopDoors();
station.UpdateFrequency = UpdateFrequency.None;
}
public override State OnUpdate(RecycleRange station, UpdateType source)
{
var inProgress = station.Doors.Exists(door => {
var angle = door.Angle;
return door.LowerLimitRad + DoorEpsilon < angle
&& angle < door.UpperLimitRad - DoorEpsilon;
});
if (!inProgress) { return new IdleState(); }
return this;
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment