RobustToolbox icon indicating copy to clipboard operation
RobustToolbox copied to clipboard

Generated YAML diff tooling

Open perryprog opened this issue 4 months ago • 8 comments

I have no idea how this would work, but it'd be nice if we had some sort of tooling that would allow us to generate a diff between two branches of all prototypes after inheritance is applied to see what components get added or removed during for example some YAML cleanup. This would make both doing and reviewing YAML cleanup PRs much easier as you would be able to tell if anything got inadvertently inherited (or removed). It should probably only show the differences of non-abstract prototypes, too, since those are all that really matter.

Would help with catching stuff like space-wizards/space-station-14#39425 and space-wizards/space-station-14#39393.

(Yeah I know this isn't really an engine feature, since ideally it's something we put in as some kind of setting for YAMLLinter, but YAMLLinter just uses PrototypeManager so that's my justification.)

perryprog avatar Aug 06 '25 17:08 perryprog

would be nice

southbridge-fur avatar Aug 06 '25 17:08 southbridge-fur

Actually make some progress hacking together a very very bad version of this (that just dumps the inherited yaml, albeit with nicely sorted fields, which you then have to diff yourself after doing the same for another commit), but I'm not sure that there's really any way to make this super user friendly. For example, the wallmount reorganization PR ends up giving me a diff of over 35,000 lines of YAML, since it wasn't just reorganization of abstract prototypes but also parenting corrections, meaning a lot of stuff got components it should've gotten. (Fixtures, damage groups, physics comp, transform comp changes, and tags are the most common.)

I wonder if a massively simplified version of this that maybe only shows components gained/lost would be sufficient. Other prototype kinds are definitely lower priority since a lot of them don't even have inheritance in the first place. Also probably not showing default values which I think I can do. (Edit: yes, silly, not showing default values makes it leagues better.)

Here's what all of the changes to ArrivalsShuttleTimer were as an example.

Big ol' diff
@@ -156766,17 +156932,21 @@ ArrivalsShuttleTimer
     netsync: True
     powerDisabled: False
     powerLoad: 100
-  - type: Appearance
-    netsync: True
-  - type: Construction
-    containers: []
-    deconstructionTarget: start
-    defaultTarget: null
-    edge: null
-    graph: Timer
+  - type: Damageable
+    damageContainer: StructuralInorganic
+    damageModifierSet: StructuralMetallic
+    healthBarThreshold: null
+    healthIcons:
+      Alive: HealthIconFine
+      Critical: HealthIconCritical
+      Dead: HealthIconDead
     netsync: True
-    node: screen
-    step: 0
+    painDamageGroups:
+    - Brute
+    - Burn
+    radiationDamageTypes:
+    - Radiation
+    rottingIcon: HealthIconRotting
   - type: DeviceNetwork
     address: ""
     autoConnect: True
@@ -156794,66 +156964,20 @@ ArrivalsShuttleTimer
     sendBroadcastAttemptEvent: False
     transmitFrequency: null
     transmitFrequencyId: null
-  - type: Electrified
-    airlockElectrifyDisabled:
-      params:
-        variation: null
-        playOffsetSeconds: 0
-        loop: False
-        referenceDistance: 1
-        rolloffFactor: 1
-        maxDistance: 15
-        pitch: 1
-        volume: 0
-      path: /Audio/Machines/airlock_electrify_on.ogg
-    airlockElectrifyEnabled:
-      params:
-        variation: null
-        playOffsetSeconds: 0
-        loop: False
-        referenceDistance: 1
-        rolloffFactor: 1
-        maxDistance: 15
-        pitch: 1
-        volume: 0
-      path: /Audio/Machines/airlock_electrify_off.ogg
-    enabled: False
-    highVoltageDamageMultiplier: 3
-    highVoltageNode: null
-    highVoltageTimeMultiplier: 2
-    isWireCut: False
-    lowVoltageNode: null
-    mediumVoltageDamageMultiplier: 2
-    mediumVoltageNode: null
-    mediumVoltageTimeMultiplier: 1.5
-    netsync: True
-    noWindowInTile: False
-    onAttacked: True
-    onBump: True
-    onHandInteract: True
-    onInteractUsing: True
-    playSoundOnShock: True
-    probability: 1
-    requirePower: True
-    shockDamage: 7.5
-    shockNoises: !type:SoundCollectionSpecifier
-      params:
-        variation: null
-        playOffsetSeconds: 0
-        loop: False
-        referenceDistance: 1
-        rolloffFactor: 1
-        maxDistance: 15
-        pitch: 1
-        volume: 0
-      collection: sparks
-    shockTime: 5
-    shockVolume: 20
-    siemensCoefficient: 1
-    usesApcPower: True
   - type: ExtensionCableReceiver
     netsync: True
     receptionRange: 3
+  - type: LightningTarget
+    damageFromLightning: 1
+    dropoff: 2
+    explosionPrototype: Default
+    hitProbability: 1
+    lightningExplode: True
+    lightningResistance: 1
+    maxTileIntensity: 5
+    netsync: True
+    priority: 1
+    totalIntensity: 25
   - type: Rotatable
     increment: 1.5707963267948966 rad
     netsync: True
@@ -156861,6 +156985,10 @@ ArrivalsShuttleTimer
     rotateWhilePulling: True
   - type: Screen
     netsync: True
+  - type: Tag
+    netsync: True
+    tags:
+    - Structure
   - type: Transform
     anchored: True
     gridTraversal: True
@@ -156870,10 +156998,10 @@ ArrivalsShuttleTimer
     pos: 0,0
     rot: 0 rad
   - type: WallMount
-    arc: 6.283185307179586 rad
+    arc: 3.1415927410125732 rad
     direction: 0 rad
     netsync: True
-  description: Displays text or time.
+  description: Displays time of arrivals shuttle ETA.
   loc: null
   localizationId: null
   name: arrivals screen

perryprog avatar Aug 08 '25 02:08 perryprog

It would also be nice if the tool could list what components got changed or added/removed alongside the diff.

K-Dynamic avatar Aug 08 '25 02:08 K-Dynamic

Ironically I say this prototype doesn't seem very helpful but it just made me realize that bar signs no longer work because they lost ApcPowerReceiver.

Edit: wait yo I'm cooking. I might actually be able to make this a reality, though still no idea how users would interface with it well.

@@ -42978,24 +43055,24 @@ ArrivalsShuttleTimer
   components:
   - type: ApcPowerReceiver
     powerLoad: 100
-  - type: Appearance
-  - type: Construction
-    graph: Timer
-    node: screen
+  - type: Damageable
+    damageContainer: StructuralInorganic
+    damageModifierSet: StructuralMetallic
   - type: DeviceNetwork
     deviceNetId: Private
     receiveFrequencyId: ArrivalsShuttleTimer
-  - type: Electrified
-    enabled: false
-    usesApcPower: true
   - type: ExtensionCableReceiver
+  - type: LightningTarget
+    priority: 1
   - type: Rotatable
   - type: Screen
+  - type: Tag
+    tags:
+    - Structure
   - type: Transform
     anchored: true
   - type: WallMount
-    arc: 360
-  description: Displays text or time.
+  description: Displays time of arrivals shuttle ETA.
   name: arrivals screen
   parent: Screen
   placement:

perryprog avatar Aug 08 '25 02:08 perryprog

i need this so badly. would love to see what youve got so far.

as far as UI goes, maybe something like the current github bot for rsis, with a dropdown for each file?

Image

mqole avatar Oct 17 '25 00:10 mqole

Unfortunately I've been way too busy with real life stuff to be able to continue anything space station related, and it'll likely be that way for some time. If this is something you (or anyone else) is interested in picking up, I can push what I had somewhere—just don't expect it to good since it was just a rough draft if I recall correctly.

perryprog avatar Oct 17 '25 01:10 perryprog

yeah, i'd be keen to take a crack at it if you're taking some time off. drop a link to what youve got and ill have a look.

mqole avatar Oct 18 '25 00:10 mqole

Sounds good—I've pushed it up to https://github.com/perryprog/RobustToolbox/tree/yaml-diffs. The idea I had was this would eventually be called into by a new part of yamllinter (via command line flag). I then tested it by adding in

 await using var pair = await PoolManager.GetServerClient();
 var server = pair.Server;
 var protoMan = server.ResolveDependency<IPrototypeManager>();
 protoMan.SaveEntityPrototypes(new("/Prototypes"));
 await pair.CleanReturnAsync();
 Console.WriteLine($"Saved in {(int)stopwatch.Elapsed.TotalMilliseconds} ms.");
 PoolManager.Shutdown();

in Content.YAMLLinter/Program.cs.

Some thoughts I remember having is it would be nice if it could have some configurability for PR authors/reviewers that would allow you to ignore certain things, like additions and/or removals of a certain component, as sometimes prototype reorganization ends up (intentionally) causing a large number of prototypes to suddenly gain an unimportant component. I also know that it's removals of components that tend to be the most significant thing, so in terms of integration with GitHub and keeping things concise, that would probably be the way to go, though I'm unsure if there is a good way to do PR integration with something like this.

perryprog avatar Oct 18 '25 18:10 perryprog