[SOLVED] [C#]Creating Gizmos/UI buttons

Started by Master Bucketsmith, September 03, 2016, 08:58:51 AM

Previous topic - Next topic

Master Bucketsmith

All right so in my search for optimizing my spotlights, I've come a great distance (with the help of several people along the way).
Alas, I hit a concrete wall on the road in that I cannot stop the turret from running TryStartShootSomething and BeginBurst, since it is extended from Building_TurretGun.

Having almost given up on that route, I went to try and copy the entire vanilla Building_TurretGun and attempt to just alter that as a new thing class for my spotlights to use.
Unfortunately it seems there are two methods that get scrambled when decompiled. I've managed to get one through using a different decompiler, but GetGizmos is still a bother.
In my search through the forum and Google I find it's a common one to be a garbled mess when decompiled, because it's a compiler generated method, or something to that extend.

I've noticed some people offer a working version, but it's always related to the mod the OP is making, which isn't a turret.
I'm having trouble understanding how I could make one specifically for the (vanilla?) turret code.
I'm not even sure what it's supposed to do, since it's scrambled.

Does anyone have any idea what this is supposed to say or where I could look into fixing it?

ILSpy
[DebuggerHidden]
public override IEnumerable<Gizmo> GetGizmos()
{
Building_TurretGun.<GetGizmos>c__Iterator107 <GetGizmos>c__Iterator = new Building_TurretGun.<GetGizmos>c__Iterator107();
<GetGizmos>c__Iterator.<>f__this = this;
Building_TurretGun.<GetGizmos>c__Iterator107 expr_0E = <GetGizmos>c__Iterator;
expr_0E.$PC = -2;
return expr_0E;
}


dotPeek
        [DebuggerHidden]
                public override IEnumerable<Gizmo> GetGizmos()
                {
                    // ISSUE: object of a compiler-generated type is created
                    // ISSUE: variable of a compiler-generated type
                    Building_TurretGun.\u003CGetGizmos\u003Ec__Iterator107 gizmosCIterator107 = new Building_TurretGun.\u003CGetGizmos\u003Ec__Iterator107()
                  {
                \u003C\u003Ef__this = this
              };
                    // ISSUE: reference to a compiler-generated field
                    gizmosCIterator107.\u0024PC = -2;
                    return (IEnumerable<Gizmo>)gizmosCIterator107;
                }

Master Bucketsmith

#1
I think I might have fixed it! :)
I used code from skullywag's old omniturret mod, simply updated and altered it to my needs.
So thank you, skullywag!
        public override IEnumerable<Gizmo> GetGizmos()
        {
            // Do base commands
            foreach (var c in base.GetGizmos())
                yield return c;

            //bool mannedByColonist = false;
            //if (mannableComp != null && mannableComp.ManningPawn != null && mannableComp.ManningPawn.Faction == Faction.OfPlayer)
                //mannedByColonist = true;
            //Thing verb;

            if (this.Gun != null)
            {
                if (mannableComp != null && mannableComp.ManningPawn != null && mannableComp.ManningPawn.Faction == Faction.OfPlayer)
                {
                    {
                        Command_Target attack = new Command_Target();
                        //Command_VerbTarget_TurretWeaponBase attack = new Command_VerbTarget_TurretWeaponBase();
                        attack.defaultLabel = "CommandSetForceAttackTarget".Translate();
                        attack.defaultDesc = "CommandSetForceAttackTargetDesc".Translate();
                        attack.icon = ContentFinder<Texture2D>.Get("UI/Commands/Attack");
                        //attack.verb = gun.PrimaryVerb;
                        attack.hotKey = KeyBindingDefOf.Misc4; //N
                        yield return attack;
                    }
                    {
                        Command_Action stop = new Command_Action();
                        stop.defaultLabel = "CommandStopForceAttack".Translate();
                        stop.defaultDesc = "CommandStopForceAttackDesc".Translate();
                        stop.icon = ContentFinder<Texture2D>.Get("UI/Commands/Halt");
                        stop.action = () => forcedTarget = TargetInfo.Invalid;
                        if (!forcedTarget.IsValid)
                            stop.Disable("CommandStopAttackFailNotForceAttacking".Translate());
                        stop.hotKey = KeyBindingDefOf.Misc5; //J
                        yield return stop;
                    }
                }
            }
        }

Master Bucketsmith

(I've been assuming that successive posts with multiple hours between them are okay - I'm sorry if it's not!)
Turns out this isn't entirely solved. The automated version didn't need a forced target gizmo, but now that I got to the point I put back the manual version and tested that, a shitton of errors pop up once I click on the 'set forced target' gizmo.

Also, the automated one is missing the gizmo for 'hold fire'. :(

Master Bucketsmith

Someone pointed me to a setting in ILSpy that allows for more usable information to be seen. It's "decompile enumerators", turn that off.

I've got this now:
        public override IEnumerable<Gizmo> GetGizmos()
        {
            foreach (Gizmo baseGizmo in base.GetGizmos())
            {
                yield return baseGizmo;
            }

            if (this.CanSetForcedTarget)
            {
                {
                    Command_VerbTarget attack = new Command_VerbTarget();
                    attack.defaultLabel = "CommandSetForceAttackTarget".Translate();
                    attack.defaultDesc = "CommandSetForceAttackTargetDesc".Translate();
                    attack.icon = ContentFinder<Texture2D>.Get("UI/Commands/Attack", true);
                    attack.verb = GunCompEq.PrimaryVerb;
                    attack.hotKey = KeyBindingDefOf.Misc4;
                    yield return attack;
                }
                {
                    Command_Action stop = new Command_Action();
                    stop.defaultLabel = "CommandStopForceAttack".Translate();
                    stop.defaultDesc = "CommandStopForceAttackDesc".Translate();
                    stop.icon = ContentFinder<Texture2D>.Get("UI/Commands/Halt", true);
                    stop.action = delegate
                    {
                        this.ResetForcedTarget();
                        SoundDefOf.TickLow.PlayOneShotOnCamera();
                    };
                    if (!this.forcedTarget.IsValid)
                    {
                        stop.Disable("CommandStopAttackFailNotForceAttacking".Translate());
                    }
                    stop.hotKey = KeyBindingDefOf.Misc5;
                    yield return stop;
                }
            }

            if (this.CanToggleHoldFire)
            {
                Command_Toggle toggleHoldFire = new Command_Toggle();
                toggleHoldFire.defaultLabel = "CommandHoldFire".Translate();
                toggleHoldFire.defaultDesc = "CommandHoldFireDesc".Translate();
                toggleHoldFire.icon = ContentFinder<Texture2D>.Get("UI/Commands/HoldFire", true);
                toggleHoldFire.hotKey = KeyBindingDefOf.Misc6;
                toggleHoldFire.toggleAction = delegate
                {
                    this.holdFire = !this.holdFire;
                    if (this.holdFire)
                    {
                        this.currentTargetInt = TargetInfo.Invalid;
                        this.burstWarmupTicksLeft = 0;
                    }
                };
                toggleHoldFire.isActive = (() => this.holdFire);
                yield return toggleHoldFire;
            }
        }

All that seems to work, except that when using force target on a manned spotlight, it can only target buildings, or it will return that the target is out of range.
I'm not sure if that's within the gizmo code or related - or if it's elsewhere in my code that just doesn't handle forced-target-aiming well. :x

Master Bucketsmith

For anyone looking into the same problem, here's a pretty complete solution;

Download the modified ILSpy from Zhentar here - https://github.com/Zhentar/ILSpy/releases/tag/0.1

And for Building_TurretGun's gizmos, it will look like so;
public override IEnumerable<Gizmo> GetGizmos()
{
IEnumerator<Gizmo> enumerator = base.GetGizmos().GetEnumerator();
while (enumerator.MoveNext())
{
Gizmo current = enumerator.Current;
yield return current;
}
if (this.CanSetForcedTarget)
{
yield return new Command_VerbTarget
{
defaultLabel = "CommandSetForceAttackTarget".Translate(),
defaultDesc = "CommandSetForceAttackTargetDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("UI/Commands/Attack", true),
verb = this.GunCompEq.PrimaryVerb,
hotKey = KeyBindingDefOf.Misc4
};
}
if (this.CanToggleHoldFire)
{
yield return new Command_Toggle
{
defaultLabel = "CommandHoldFire".Translate(),
defaultDesc = "CommandHoldFireDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("UI/Commands/HoldFire", true),
hotKey = KeyBindingDefOf.Misc6,
toggleAction = delegate
{
this.<>f__this.holdFire = !this.<>f__this.holdFire;
if (this.<>f__this.holdFire)
{
this.<>f__this.currentTargetInt = TargetInfo.Invalid;
this.<>f__this.burstWarmupTicksLeft = 0;
}
},
isActive = (() => this.<>f__this.holdFire)
};
}
yield break;
}

The only thing left to manually change is stuff like:
this.<>f__this.holdFire = !this.<>f__this.holdFire;
to
this.holdFire = !this.holdFire;
:)

Side-note; the problem I'm having with the forced target button is not related to the code of the button, but the functionality of my mod.