silkedit 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. checksums.yaml +7 -0
  2. data/.rbcli +0 -0
  3. data/CHANGELOG.md +7 -0
  4. data/CODE_OF_CONDUCT.md +132 -0
  5. data/LICENSE.txt +169 -0
  6. data/README.md +302 -0
  7. data/Rakefile +8 -0
  8. data/exe/silkedit +13 -0
  9. data/lib/commands/backup_restore.rb +25 -0
  10. data/lib/commands/cheat.rb +74 -0
  11. data/lib/commands/edit_diff.rb +47 -0
  12. data/lib/commands/examples/command.rb +51 -0
  13. data/lib/commands/examples/script.rb +36 -0
  14. data/lib/commands/journal.rb +34 -0
  15. data/lib/commands/permasave_permaload.rb +62 -0
  16. data/lib/commands/scripts/.keep +0 -0
  17. data/lib/commands/unpack_repack.rb +27 -0
  18. data/lib/commands/zone_mkzone.rb +103 -0
  19. data/lib/config/config.rb +28 -0
  20. data/lib/config/envvars.rb +23 -0
  21. data/lib/config/hooks.rb +22 -0
  22. data/lib/config/logger.rb +36 -0
  23. data/lib/config/parser.rb +34 -0
  24. data/lib/config/updatechecker.rb +12 -0
  25. data/lib/silkedit/cheats/cheatengine.rb +33 -0
  26. data/lib/silkedit/cheats/hollow_knight_cheats.rb +5 -0
  27. data/lib/silkedit/cheats/merger.rb +107 -0
  28. data/lib/silkedit/cheats/silksong_cheats.rb +161 -0
  29. data/lib/silkedit/cheats/silksong_enemyjournal.rb +120 -0
  30. data/lib/silkedit/cheats/silksong_zoner.rb +98 -0
  31. data/lib/silkedit/config/savegame.yaml +13 -0
  32. data/lib/silkedit/config/silkedit.yaml +6 -0
  33. data/lib/silkedit/config/silksong/cheatdata.yaml +1341 -0
  34. data/lib/silkedit/config/silksong/enemylist.yaml +1424 -0
  35. data/lib/silkedit/config/silksong/old.yaml +4345 -0
  36. data/lib/silkedit/config/silksong/permasaves.yaml +12 -0
  37. data/lib/silkedit/config/silksong/unfinished.yaml +628 -0
  38. data/lib/silkedit/config/silksong/zones.yaml +1738 -0
  39. data/lib/silkedit/images/.keep +0 -0
  40. data/lib/silkedit/images/silksong/Aknid.png +0 -0
  41. data/lib/silkedit/images/silksong/Alita.png +0 -0
  42. data/lib/silkedit/images/silksong/Barnak.png +0 -0
  43. data/lib/silkedit/images/silksong/Beastfly.png +0 -0
  44. data/lib/silkedit/images/silksong/Bell_Beast.png +0 -0
  45. data/lib/silkedit/images/silksong/Bell_Eater.png +0 -0
  46. data/lib/silkedit/images/silksong/Bloatroach.png +0 -0
  47. data/lib/silkedit/images/silksong/Broodmother.png +0 -0
  48. data/lib/silkedit/images/silksong/Brushflit.png +0 -0
  49. data/lib/silkedit/images/silksong/Burning_Bug.png +0 -0
  50. data/lib/silkedit/images/silksong/Caranid.png +0 -0
  51. data/lib/silkedit/images/silksong/Choir_Bellbearer.png +0 -0
  52. data/lib/silkedit/images/silksong/Choir_Clapper.png +0 -0
  53. data/lib/silkedit/images/silksong/Choir_Elder.png +0 -0
  54. data/lib/silkedit/images/silksong/Choir_Flyer.png +0 -0
  55. data/lib/silkedit/images/silksong/Choir_Hornhead.png +0 -0
  56. data/lib/silkedit/images/silksong/Choir_Pouncer.png +0 -0
  57. data/lib/silkedit/images/silksong/Choristor.png +0 -0
  58. data/lib/silkedit/images/silksong/Clawmaiden.png +0 -0
  59. data/lib/silkedit/images/silksong/Clover_Dancers.png +0 -0
  60. data/lib/silkedit/images/silksong/Cloverstag.png +0 -0
  61. data/lib/silkedit/images/silksong/Cogwork_Choirbug.png +0 -0
  62. data/lib/silkedit/images/silksong/Cogwork_Clapper.png +0 -0
  63. data/lib/silkedit/images/silksong/Cogwork_Cleanser.png +0 -0
  64. data/lib/silkedit/images/silksong/Cogwork_Crawler.png +0 -0
  65. data/lib/silkedit/images/silksong/Cogwork_Dancers.png +0 -0
  66. data/lib/silkedit/images/silksong/Cogwork_Defender.png +0 -0
  67. data/lib/silkedit/images/silksong/Cogwork_Hauler.png +0 -0
  68. data/lib/silkedit/images/silksong/Cogwork_Spine.png +0 -0
  69. data/lib/silkedit/images/silksong/Cogwork_Underfly.png +0 -0
  70. data/lib/silkedit/images/silksong/Cogworker.png +0 -0
  71. data/lib/silkedit/images/silksong/Conchfly.png +0 -0
  72. data/lib/silkedit/images/silksong/Coral_Furm.png +0 -0
  73. data/lib/silkedit/images/silksong/Corrcrust_Karaka.png +0 -0
  74. data/lib/silkedit/images/silksong/Covetous_Pilgrim.png +0 -0
  75. data/lib/silkedit/images/silksong/Craggler.png +0 -0
  76. data/lib/silkedit/images/silksong/Cragglite.png +0 -0
  77. data/lib/silkedit/images/silksong/Craw.png +0 -0
  78. data/lib/silkedit/images/silksong/Craw_Juror.png +0 -0
  79. data/lib/silkedit/images/silksong/Crawfather.png +0 -0
  80. data/lib/silkedit/images/silksong/Crust_King_Khann.png +0 -0
  81. data/lib/silkedit/images/silksong/Crustcrag.png +0 -0
  82. data/lib/silkedit/images/silksong/Crustcrawler.png +0 -0
  83. data/lib/silkedit/images/silksong/Deep_Diver.png +0 -0
  84. data/lib/silkedit/images/silksong/Disgraced_Chef_Lugoli.png +0 -0
  85. data/lib/silkedit/images/silksong/Drapefly.png +0 -0
  86. data/lib/silkedit/images/silksong/Drapelord.png +0 -0
  87. data/lib/silkedit/images/silksong/Drapemite.png +0 -0
  88. data/lib/silkedit/images/silksong/Dreg_Catcher.png +0 -0
  89. data/lib/silkedit/images/silksong/Dreg_Husk.png +0 -0
  90. data/lib/silkedit/images/silksong/Dregwheel.png +0 -0
  91. data/lib/silkedit/images/silksong/Driftlin.png +0 -0
  92. data/lib/silkedit/images/silksong/Driznarga.png +0 -0
  93. data/lib/silkedit/images/silksong/Driznit.png +0 -0
  94. data/lib/silkedit/images/silksong/Ductsucker.png +0 -0
  95. data/lib/silkedit/images/silksong/Elder_Pilgrim.png +0 -0
  96. data/lib/silkedit/images/silksong/Envoy.png +0 -0
  97. data/lib/silkedit/images/silksong/Escalion.png +0 -0
  98. data/lib/silkedit/images/silksong/Father_of_the_Flame.png +0 -0
  99. data/lib/silkedit/images/silksong/Fertid.png +0 -0
  100. data/lib/silkedit/images/silksong/First_Sinner.png +0 -0
  101. data/lib/silkedit/images/silksong/Flapping_Fertid.png +0 -0
  102. data/lib/silkedit/images/silksong/Flintbeetle.png +0 -0
  103. data/lib/silkedit/images/silksong/Flintflame_Flyer.png +0 -0
  104. data/lib/silkedit/images/silksong/Flintstone_Flyer.png +0 -0
  105. data/lib/silkedit/images/silksong/Fluttermite.png +0 -0
  106. data/lib/silkedit/images/silksong/Forebrothers_Signis_&_Gron.png +0 -0
  107. data/lib/silkedit/images/silksong/Fourth_Chorus.png +0 -0
  108. data/lib/silkedit/images/silksong/Freshfly.png +0 -0
  109. data/lib/silkedit/images/silksong/Furm.png +0 -0
  110. data/lib/silkedit/images/silksong/Gahlia.png +0 -0
  111. data/lib/silkedit/images/silksong/Gargant_Gloom.png +0 -0
  112. data/lib/silkedit/images/silksong/Garpid.png +0 -0
  113. data/lib/silkedit/images/silksong/Giant_Drapemite.png +0 -0
  114. data/lib/silkedit/images/silksong/Gloomsac.png +0 -0
  115. data/lib/silkedit/images/silksong/Grand_Mother_Silk.png +0 -0
  116. data/lib/silkedit/images/silksong/Grand_Reed.png +0 -0
  117. data/lib/silkedit/images/silksong/Great_Conchfly.png +0 -0
  118. data/lib/silkedit/images/silksong/Groal_the_Great.png +0 -0
  119. data/lib/silkedit/images/silksong/Grom.png +0 -0
  120. data/lib/silkedit/images/silksong/Gromling.png +0 -0
  121. data/lib/silkedit/images/silksong/Guardfly.png +0 -0
  122. data/lib/silkedit/images/silksong/Gurr_the_Outcast.png +0 -0
  123. data/lib/silkedit/images/silksong/Hardbone_Elder.png +0 -0
  124. data/lib/silkedit/images/silksong/Hardbone_Hopper.png +0 -0
  125. data/lib/silkedit/images/silksong/Hoker.png +0 -0
  126. data/lib/silkedit/images/silksong/Huge_Flea.png +0 -0
  127. data/lib/silkedit/images/silksong/Imoba.png +0 -0
  128. data/lib/silkedit/images/silksong/Judge.png +0 -0
  129. data/lib/silkedit/images/silksong/Kai.png +0 -0
  130. data/lib/silkedit/images/silksong/Kakri.png +0 -0
  131. data/lib/silkedit/images/silksong/Karak_Gor.png +0 -0
  132. data/lib/silkedit/images/silksong/Karaka.png +0 -0
  133. data/lib/silkedit/images/silksong/Kilik.png +0 -0
  134. data/lib/silkedit/images/silksong/Kindanir.png +0 -0
  135. data/lib/silkedit/images/silksong/Lace.png +0 -0
  136. data/lib/silkedit/images/silksong/Lampbearer.png +0 -0
  137. data/lib/silkedit/images/silksong/Last_Claw.png +0 -0
  138. data/lib/silkedit/images/silksong/Last_Judge.png +0 -0
  139. data/lib/silkedit/images/silksong/Lavalarga.png +0 -0
  140. data/lib/silkedit/images/silksong/Lavalug.png +0 -0
  141. data/lib/silkedit/images/silksong/Leaf_Glider.png +0 -0
  142. data/lib/silkedit/images/silksong/Leaf_Roller.png +0 -0
  143. data/lib/silkedit/images/silksong/Lost_Garmond.png +0 -0
  144. data/lib/silkedit/images/silksong/Lost_Lace.png +0 -0
  145. data/lib/silkedit/images/silksong/Maestro.png +0 -0
  146. data/lib/silkedit/images/silksong/Marrowmaw.png +0 -0
  147. data/lib/silkedit/images/silksong/Massive_Mossgrub.png +0 -0
  148. data/lib/silkedit/images/silksong/Mawling.png +0 -0
  149. data/lib/silkedit/images/silksong/Memoria.png +0 -0
  150. data/lib/silkedit/images/silksong/Minister.png +0 -0
  151. data/lib/silkedit/images/silksong/Miremite.png +0 -0
  152. data/lib/silkedit/images/silksong/Mite.png +0 -0
  153. data/lib/silkedit/images/silksong/Mitemother.png +0 -0
  154. data/lib/silkedit/images/silksong/Mnemonid.png +0 -0
  155. data/lib/silkedit/images/silksong/Mnemonord.png +0 -0
  156. data/lib/silkedit/images/silksong/Moorwing.png +0 -0
  157. data/lib/silkedit/images/silksong/Mortician.png +0 -0
  158. data/lib/silkedit/images/silksong/Moss_Mother.png +0 -0
  159. data/lib/silkedit/images/silksong/Mossgrub.png +0 -0
  160. data/lib/silkedit/images/silksong/Mossmir.png +0 -0
  161. data/lib/silkedit/images/silksong/Mothleaf_Lagnia.png +0 -0
  162. data/lib/silkedit/images/silksong/Muckmaggot.png +0 -0
  163. data/lib/silkedit/images/silksong/Muckroach.png +0 -0
  164. data/lib/silkedit/images/silksong/Nuphar.png +0 -0
  165. data/lib/silkedit/images/silksong/Nyleth.png +0 -0
  166. data/lib/silkedit/images/silksong/Overgrown_Pilgrim.png +0 -0
  167. data/lib/silkedit/images/silksong/Palestag.png +0 -0
  168. data/lib/silkedit/images/silksong/Pendra.png +0 -0
  169. data/lib/silkedit/images/silksong/Pendragor.png +0 -0
  170. data/lib/silkedit/images/silksong/Penitent.png +0 -0
  171. data/lib/silkedit/images/silksong/Phacia.png +0 -0
  172. data/lib/silkedit/images/silksong/Phantom.png +0 -0
  173. data/lib/silkedit/images/silksong/Pharlid.png +0 -0
  174. data/lib/silkedit/images/silksong/Pharlid_Diver.png +0 -0
  175. data/lib/silkedit/images/silksong/Pilgrim_Bellbearer.png +0 -0
  176. data/lib/silkedit/images/silksong/Pilgrim_Groveller.png +0 -0
  177. data/lib/silkedit/images/silksong/Pilgrim_Guide.png +0 -0
  178. data/lib/silkedit/images/silksong/Pilgrim_Hiker.png +0 -0
  179. data/lib/silkedit/images/silksong/Pilgrim_Hornfly.png +0 -0
  180. data/lib/silkedit/images/silksong/Pilgrim_Hulk.png +0 -0
  181. data/lib/silkedit/images/silksong/Pilgrim_Pouncer.png +0 -0
  182. data/lib/silkedit/images/silksong/Pinstress.png +0 -0
  183. data/lib/silkedit/images/silksong/Plasmid.png +0 -0
  184. data/lib/silkedit/images/silksong/Plasmidas.png +0 -0
  185. data/lib/silkedit/images/silksong/Plasmified_Zango.png +0 -0
  186. data/lib/silkedit/images/silksong/Pokenabbin.png +0 -0
  187. data/lib/silkedit/images/silksong/Pollenica.png +0 -0
  188. data/lib/silkedit/images/silksong/Pond_Skipper.png +0 -0
  189. data/lib/silkedit/images/silksong/Pondcatcher.png +0 -0
  190. data/lib/silkedit/images/silksong/Puny_Penitent.png +0 -0
  191. data/lib/silkedit/images/silksong/Reed.png +0 -0
  192. data/lib/silkedit/images/silksong/Rhinogrund.png +0 -0
  193. data/lib/silkedit/images/silksong/Roachcatcher.png +0 -0
  194. data/lib/silkedit/images/silksong/Roachfeeder.png +0 -0
  195. data/lib/silkedit/images/silksong/Roachkeeper.png +0 -0
  196. data/lib/silkedit/images/silksong/Roachserver.png +0 -0
  197. data/lib/silkedit/images/silksong/Sandcarver.png +0 -0
  198. data/lib/silkedit/images/silksong/Savage_Beastfly.png +0 -0
  199. data/lib/silkedit/images/silksong/Scabfly.png +0 -0
  200. data/lib/silkedit/images/silksong/Scrollreader.png +0 -0
  201. data/lib/silkedit/images/silksong/Second_Sentinel.png +0 -0
  202. data/lib/silkedit/images/silksong/Servitor_Boran.png +0 -0
  203. data/lib/silkedit/images/silksong/Servitor_Ignim.png +0 -0
  204. data/lib/silkedit/images/silksong/Shadow_Charger.png +0 -0
  205. data/lib/silkedit/images/silksong/Shadow_Creeper_(Silksong).png +0 -0
  206. data/lib/silkedit/images/silksong/Shardillard.png +0 -0
  207. data/lib/silkedit/images/silksong/Shellwood_Gnat.png +0 -0
  208. data/lib/silkedit/images/silksong/Shrine_Guardian_Seth.png +0 -0
  209. data/lib/silkedit/images/silksong/Silk_Snipper.png +0 -0
  210. data/lib/silkedit/images/silksong/Sister_Splinter.png +0 -0
  211. data/lib/silkedit/images/silksong/Skarr_Scout.png +0 -0
  212. data/lib/silkedit/images/silksong/Skarr_Stalker.png +0 -0
  213. data/lib/silkedit/images/silksong/Skarrgard.png +0 -0
  214. data/lib/silkedit/images/silksong/Skarrlid.png +0 -0
  215. data/lib/silkedit/images/silksong/Skarrsinger_Karmelita.png +0 -0
  216. data/lib/silkedit/images/silksong/Skarrwing.png +0 -0
  217. data/lib/silkedit/images/silksong/Skrill.png +0 -0
  218. data/lib/silkedit/images/silksong/Skull_Brute.png +0 -0
  219. data/lib/silkedit/images/silksong/Skull_Scuttler.png +0 -0
  220. data/lib/silkedit/images/silksong/Skull_Tyrant.png +0 -0
  221. data/lib/silkedit/images/silksong/Skullwing.png +0 -0
  222. data/lib/silkedit/images/silksong/Slubberlug.png +0 -0
  223. data/lib/silkedit/images/silksong/Smelt_Shoveller.png +0 -0
  224. data/lib/silkedit/images/silksong/Smokerock_Sifter.png +0 -0
  225. data/lib/silkedit/images/silksong/Snitchfly.png +0 -0
  226. data/lib/silkedit/images/silksong/Spear_Skarr.png +0 -0
  227. data/lib/silkedit/images/silksong/Spinebeak_Kai.png +0 -0
  228. data/lib/silkedit/images/silksong/Spit_Squit.png +0 -0
  229. data/lib/silkedit/images/silksong/Splinter.png +0 -0
  230. data/lib/silkedit/images/silksong/Splinterbark.png +0 -0
  231. data/lib/silkedit/images/silksong/Splinterhorn.png +0 -0
  232. data/lib/silkedit/images/silksong/Squatcraw.png +0 -0
  233. data/lib/silkedit/images/silksong/Squatcraw_Juror.png +0 -0
  234. data/lib/silkedit/images/silksong/Squirrm.png +0 -0
  235. data/lib/silkedit/images/silksong/Steelspine_Kai.png +0 -0
  236. data/lib/silkedit/images/silksong/Stilkin.png +0 -0
  237. data/lib/silkedit/images/silksong/Stilkin_Trapper.png +0 -0
  238. data/lib/silkedit/images/silksong/Summoned_Saviour.png +0 -0
  239. data/lib/silkedit/images/silksong/Surgeon.png +0 -0
  240. data/lib/silkedit/images/silksong/Swamp_Squit.png +0 -0
  241. data/lib/silkedit/images/silksong/Tallcraw.png +0 -0
  242. data/lib/silkedit/images/silksong/Tallcraw_Juror.png +0 -0
  243. data/lib/silkedit/images/silksong/Tarmite.png +0 -0
  244. data/lib/silkedit/images/silksong/The_Unravelled.png +0 -0
  245. data/lib/silkedit/images/silksong/Thread_Raker.png +0 -0
  246. data/lib/silkedit/images/silksong/Tormented_Trobbio.png +0 -0
  247. data/lib/silkedit/images/silksong/Trobbio.png +0 -0
  248. data/lib/silkedit/images/silksong/Undercrank.png +0 -0
  249. data/lib/silkedit/images/silksong/Underloft.png +0 -0
  250. data/lib/silkedit/images/silksong/Underpoke.png +0 -0
  251. data/lib/silkedit/images/silksong/Underscrub.png +0 -0
  252. data/lib/silkedit/images/silksong/Undersweep.png +0 -0
  253. data/lib/silkedit/images/silksong/Underworker.png +0 -0
  254. data/lib/silkedit/images/silksong/Vaultborn.png +0 -0
  255. data/lib/silkedit/images/silksong/Vaultkeeper.png +0 -0
  256. data/lib/silkedit/images/silksong/Verdanir.png +0 -0
  257. data/lib/silkedit/images/silksong/Vicious_Caranid.png +0 -0
  258. data/lib/silkedit/images/silksong/Void_Mass.png +0 -0
  259. data/lib/silkedit/images/silksong/Void_Tendrils_(Silksong).png +0 -0
  260. data/lib/silkedit/images/silksong/Voltvyrm.png +0 -0
  261. data/lib/silkedit/images/silksong/Wardenfly.png +0 -0
  262. data/lib/silkedit/images/silksong/Watcher_at_the_Edge.png +0 -0
  263. data/lib/silkedit/images/silksong/Widow.png +0 -0
  264. data/lib/silkedit/images/silksong/Winged_Furm.png +0 -0
  265. data/lib/silkedit/images/silksong/Winged_Lifeseed.png +0 -0
  266. data/lib/silkedit/images/silksong/Winged_Pilgrim.png +0 -0
  267. data/lib/silkedit/images/silksong/Winged_Pilgrim_Bellbearer.png +0 -0
  268. data/lib/silkedit/images/silksong/Wingmould_(Silksong).png +0 -0
  269. data/lib/silkedit/images/silksong/Wisp.png +0 -0
  270. data/lib/silkedit/images/silksong/Wood_Wasp.png +0 -0
  271. data/lib/silkedit/images/silksong/Wraith.png +0 -0
  272. data/lib/silkedit/images/silksong/Yago.png +0 -0
  273. data/lib/silkedit/images/silksong/Yuma.png +0 -0
  274. data/lib/silkedit/images/silksong/Yumama.png +0 -0
  275. data/lib/silkedit/savegame/crypto.rb +25 -0
  276. data/lib/silkedit/savegame/diff.rb +159 -0
  277. data/lib/silkedit/savegame/packer.rb +75 -0
  278. data/lib/silkedit/savegame/savefile.rb +157 -0
  279. data/lib/silkedit/util/system.rb +37 -0
  280. data/lib/silkedit/version.rb +5 -0
  281. data/lib/silkedit.rb +9 -0
  282. data/sig/silkedit.rbs +4 -0
  283. metadata +505 -0
@@ -0,0 +1,33 @@
1
+ module Silkedit::Cheat
2
+ class Engine
3
+ def initialize(savedata)
4
+ @data = savedata
5
+ game = detect_game(@data)
6
+ @modules = %w[Cheats Zoner Journaler].map { |type| [type, Silkedit::Cheat.const_get("#{game}#{type}")]}.to_h
7
+ @modules.each_value { |mod| self.extend(mod) }
8
+ end
9
+
10
+ def apply_cheat(cheat, *args)
11
+ return :no_cheat unless cheat_exists?(cheat.to_s)
12
+ self.send(cheat.to_sym, *args)
13
+ end
14
+
15
+ def apply_cheats(cheats)
16
+ cheats.map { |cheat| apply_cheat(cheat) }
17
+ end
18
+
19
+ def list_cheats
20
+ @modules['Cheats'].instance_methods.map(&:to_s).sort
21
+ end
22
+
23
+ def cheat_exists?(cheat)
24
+ list_cheats.include?(cheat)
25
+ end
26
+
27
+ private
28
+
29
+ def detect_game(data = nil)
30
+ (data || @data).key?('firstGeo') ? 'HollowKnight' : 'Silksong'
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ module Silkedit::Cheat
2
+ module HollowKnightCheats
3
+
4
+ end
5
+ end
@@ -0,0 +1,107 @@
1
+ module Silkedit::Cheat
2
+ def self.merge_cheat(data, cheat, should_merge_arrays: true, force_soft_reqs: false, enforce_min_act: false)
3
+ # 1. Check act requirement
4
+ game_act = self.get_game_act(data)
5
+ Rbcli.log.debug "Game act is #{game_act}, required act is #{cheat['min_act']}", 'CHEATS'
6
+ return :failed_act_check if enforce_min_act && cheat.key?('min_act') && game_act < cheat['min_act']
7
+
8
+ # 2. Check hard reqs and abort if not met
9
+ if cheat.key?('hard_reqs') && !cheat['hard_reqs'].nil? && !cheat['hard_reqs'].empty?
10
+ return :failed_hard_reqs unless verify_hash(data, cheat['hard_reqs'])
11
+ end
12
+
13
+ # 3. Check soft reqs, and either queue them to be applied or abort
14
+ queue_soft_reqs = false
15
+ if cheat.key?('soft_reqs') && !cheat['soft_reqs'].nil? && !cheat['soft_reqs'].empty?
16
+ unless verify_hash(data, cheat['soft_reqs'])
17
+ return :failed_soft_reqs unless force_soft_reqs
18
+ queue_soft_reqs = true
19
+ end
20
+ end
21
+
22
+ # 4. Apply cheat
23
+ self.merge_hash(data, cheat['soft_reqs'], should_merge_arrays: true) if queue_soft_reqs
24
+ self.merge_hash(data, cheat['data'], should_merge_arrays: should_merge_arrays)
25
+ :success
26
+ end
27
+
28
+ def self.merge_hash(data, cheat, should_merge_arrays: true)
29
+ cheat.each_key do |k|
30
+ if cheat[k].is_a?(Hash) && data[k].is_a?(Hash)
31
+ merge_hash(data[k], cheat[k])
32
+ elsif should_merge_arrays && cheat[k].is_a?(Array) && data[k].is_a?(Array)
33
+ if cheat[k][0].is_a?(Hash)
34
+ data[k] = merge_arrays_by_hash_keys(data[k], cheat[k])
35
+ else
36
+ data[k].merge!(cheat[k])
37
+ data[k].uniq!
38
+ end
39
+ else
40
+ data[k] = cheat[k]
41
+ end
42
+ end
43
+ true
44
+ end
45
+
46
+ def self.merge_arrays_by_hash_keys(data, cheat)
47
+ return data unless data.is_a?(Array) && cheat.is_a?(Array) && cheat.first.is_a?(Hash)
48
+ if data.empty?
49
+ data = cheat
50
+ return data
51
+ end
52
+ # First determine the primary key(s) for the object
53
+ pkeys = []
54
+ [%w[Name], %w[SceneName ID]].each do |pkey_arr|
55
+ pkeys = pkey_arr if pkey_arr.all? { |k| data.first.key?(k) || cheat.first.key?(k) }
56
+ end
57
+ cheat.each do |c|
58
+ idx = data.find_index { |d| d.is_a?(Hash) && pkeys.all? { |k| d.key?(k) && d[k] == c[k] } }
59
+ if idx
60
+ self.merge_hash(data[idx], c, should_merge_arrays: true)
61
+ else
62
+ data << c
63
+ end
64
+ end
65
+ data
66
+ end
67
+
68
+ def self.verify_hash(data, reqs)
69
+ reqs.each_key do |k|
70
+ if reqs[k].is_a?(Hash) && data[k].is_a?(Hash)
71
+ return false unless verify_hash(data[k], reqs[k])
72
+ elsif reqs[k].is_a?(Array) && data[k].is_a?(Array)
73
+ if reqs[k].first.is_a?(Hash)
74
+ return false unless verify_array_of_hashes(data[k], reqs[k])
75
+ else
76
+ return false unless reqs[k].all? { |r| data[k].include?(r) }
77
+ end
78
+ else
79
+ return false unless data[k] == reqs[k]
80
+ end
81
+ end
82
+ true
83
+ end
84
+
85
+ def self.verify_array_of_hashes(data, reqs)
86
+ # First determine the primary key(s) for the object
87
+ pkeys = []
88
+ [%w[Name], %w[SceneName ID]].each do |pkey_arr|
89
+ pkeys = pkey_arr if pkey_arr.all? { |k| data.first.key?(k) || reqs.first.key?(k) }
90
+ end
91
+ reqs.each do |r|
92
+ idx = data.find_index { |d| d.is_a?(Hash) && pkeys.all? { |k| d.key?(k) && d[k] == r[k] } }
93
+ return false unless idx && self.verify_hash(data[idx], r)
94
+ end
95
+ true
96
+ end
97
+
98
+ def self.get_game_act(data)
99
+ if %w[act3MapUpdated act3_wokeup].any? { |c| data['playerData'][c] }
100
+ 3
101
+ elsif %w[act2started visitedCitadel defeatedLastJudge].any? { |c| data['playerData'][c] }
102
+ 2
103
+ else
104
+ 1
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,161 @@
1
+ require 'yaml'
2
+
3
+ module Silkedit::Cheat
4
+ module SilksongCheats
5
+ @cheatdata = YAML.safe_load_file(File.join(Silkedit::LIBDIR, 'config', 'silksong', 'cheatdata.yaml'), symbolize_names: false)
6
+ @cheatdata['cheats'].each do |cheat, cht_data|
7
+ next if self.instance_methods.include?(cheat.to_sym)
8
+ self.define_method(cheat.to_sym) do
9
+ Rbcli.log.info "Applying cheat #{cheat}", 'CHEATS'
10
+ Silkedit::Cheat.merge_cheat(@data, cht_data, should_merge_arrays: true)
11
+ end
12
+ end
13
+
14
+ def unkill
15
+ Rbcli.log.info 'Reviving from death', 'CHEATS'
16
+ if @data['playerData']['permadeathMode'] == 2
17
+ @data['playerData']['permadeathMode'] = 1
18
+ end
19
+ @data['playerData']['geo'] += @data['playerData']['HeroCorpseMoneyPool']
20
+ @data['playerData']['HeroDeathScenePos'] = { 'x' => 0.0, 'y' => 0.0 }
21
+ @data['playerData']['HeroDeathSceneSize'] = { 'x' => 0.0, 'y' => 0.0 }
22
+ @data['playerData']['HeroCorpseType'] = 0
23
+ @data['playerData']['HeroCorpseMoneyPool'] = 0
24
+ @data['playerData']['hazardRespawnFacing'] = 0
25
+ @data['playerData']['IsSilkSpoolBroken'] = false
26
+ @data['playerData'].delete('HeroCorpseMarkerGuid')
27
+ @data['playerData'].delete('HeroCorpseScene')
28
+ end
29
+
30
+ def refresh
31
+ self.max_shards
32
+ self.max_liquids
33
+ end
34
+
35
+ def max_everything
36
+ backup_data = @data.dup
37
+ result = %w[
38
+ max_health
39
+ max_silk
40
+ max_weapon
41
+ max_tool_upgrades
42
+ max_liquids
43
+ all_abilities
44
+ all_crests
45
+ all_crest_unlocks
46
+ all_eva_upgrades
47
+ all_spells
48
+ all_tools
49
+ give_consumables
50
+ max_rosaries
51
+ max_shards
52
+ ].map { |cht| self.send(cht.to_sym) }
53
+ if result.all?(:success)
54
+ :success
55
+ else
56
+ @data = backup_data
57
+ result.reject { |r| r == :success }.first
58
+ end
59
+ end
60
+
61
+ def max_shards
62
+ Rbcli.log.info 'Applying cheat max_shards', 'CHEATS'
63
+ @data['playerData']['ShellShards'] = 400 + (@data['playerData']['ToolPouchUpgrades'] || 0) * 100
64
+ :success
65
+ end
66
+
67
+ def all_crests
68
+ cheatdata = Silkedit::Cheat::SilksongCheats.module_eval { @cheatdata }
69
+ Rbcli.log.info "Applying cheat all_crests", 'CHEATS'
70
+ Silkedit::Cheat.merge_cheat(@data, cheatdata['reference']['all_crests'], should_merge_arrays: true)
71
+ %w[CurrentCrestID PreviousCrestID].each do |equip|
72
+ %w[Hunter Hunter_v2].each do |hunter_crest_version|
73
+ @data['playerData'][equip] = 'Hunter_v3' if @data['playerData'][equip] == hunter_crest_version
74
+ end
75
+ end
76
+ :success
77
+ end
78
+
79
+ def all_crest_unlocks
80
+ Rbcli.log.info 'Applying cheat all_crest_unlocks', 'CHEATS'
81
+ cheatdata = Silkedit::Cheat::SilksongCheats.module_eval { @cheatdata }
82
+ @data['playerData']['ToolEquips']['savedData'].each do |crest|
83
+ if crest['Data']['Slots'].nil? || crest['Data']['Slots'].empty?
84
+ newcrest = cheatdata['reference']['full_crests']['playerData']['ToolEquips']['savedData'].find { |c| c['Name'] == crest['Name'] }
85
+ next if newcrest.nil?
86
+ crest['Data'] = {} if crest['Data'].nil?
87
+ crest['Data']['Slots'] = newcrest['Data']['Slots'] if newcrest.key?('Data') && newcrest['Data'].key?('Slots')
88
+ end
89
+ crest['Data']['Slots'].each { |slot| slot['IsUnlocked'] = true }
90
+ end
91
+ :success
92
+ end
93
+
94
+ def overcharge_tools
95
+ Rbcli.log.info "Applying cheat overcharge_tools", 'CHEATS'
96
+ @data['playerData']['Tools']['savedData'].each do |tool|
97
+ tool['Data']['AmountLeft'] = 1000
98
+ end
99
+ :success
100
+ end
101
+
102
+ def toggle_map_reveal
103
+ @data['playerData']['mapAllRooms'] = !@data['playerData']['mapAllRooms']
104
+ Rbcli.log.info "Full map reveal is #{@data['playerData']['mapAllRooms'] ? 'enabled' : 'disabled'}", 'CHEATS'
105
+ :success
106
+ end
107
+
108
+ def toggle_flea_reveal
109
+ flea_keys = @data['playerData'].keys.select { |k| k.start_with?('hasPinFlea') }
110
+ is_enabled = flea_keys.all? { |k| @data['playerData'][k] }
111
+ flea_keys.each { |k| @data[k] = !is_enabled }
112
+ Rbcli.log.info "Flea locations are #{is_enabled ? 'hidden' : 'revealed'} on map", 'CHEATS'
113
+ :success
114
+ end
115
+
116
+ def toggle_cloakless
117
+ if @data['playerData']['CurrentCrestID'] != 'Cloakless'
118
+ Rbcli.log.info 'Going cloakless', 'CHEATS'
119
+ @data['playerData']['TempGeoStore'] = @data['playerData']['geo']
120
+ @data['playerData']['geo'] = 0
121
+ @data['playerData']['TempShellShardStore'] = @data['playerData']['ShellShards']
122
+ @data['playerData']['ShellShards'] = 0
123
+ @data['playerData']['PreviousCrestID'] = @data['playerData']['CurrentCrestID']
124
+ @data['playerData']['CurrentCrestID'] = 'Cloakless'
125
+ @data['playerData']['slab_cloak_battle_encountered'] = false
126
+ @data['playerData']['slab_cloak_battle_completed'] = false
127
+ @data['playerData']['IsSilkSpoolBroken'] = true
128
+ unless @data['playerData']['ToolEquips']['savedData'].find { |e| e['Name'] == 'Cloakless' }
129
+ cheatdata = Silkedit::Cheat::SilksongCheats.module_eval { @cheatdata }
130
+ @data['playerData']['ToolEquips']['savedData'].append(cheatdata['reference']['cloakless']['playerData']['ToolEquips']['savedData'].first)
131
+ end
132
+ else
133
+ Rbcli.log.info 'Recovering cloak', 'CHEATS'
134
+ @data['playerData']['geo'] = @data['playerData']['TempGeoStore']
135
+ @data['playerData']['TempGeoStore'] = 0
136
+ @data['playerData']['ShellShards'] = @data['playerData']['TempShellShardStore']
137
+ @data['playerData']['TempShellShardStore'] = 0
138
+ @data['playerData']['CurrentCrestID'] = @data['playerData']['PreviousCrestID']
139
+ @data['playerData']['PreviousCrestID'] = 'Cloakless'
140
+ # @data['playerData']['slab_cloak_battle_encountered'] = true
141
+ # @data['playerData']['slab_cloak_battle_completed'] = true
142
+ @data['playerData']['IsSilkSpoolBroken'] = false
143
+ end
144
+ :success
145
+ end
146
+
147
+ def toggle_permadeath_mode
148
+ toggle = @data['playerData']['permadeathMode'] == 0
149
+ Rbcli.log.info "Toggling permadeath mode #{toggle ? 'ON' : 'OFF'}", 'CHEATS'
150
+ @data['playerData']['permadeathMode'] = toggle ? 1 : 0
151
+ :success
152
+ end
153
+
154
+ def toggle_fly_mode
155
+ toggle = @data['playerData']['infiniteAirJump'] == false
156
+ Rbcli.log.info "Toggling fly mode #{toggle ? 'ON' : 'OFF'}", 'CHEATS'
157
+ @data['playerData']['infiniteAirJump'] = toggle ? true : false
158
+ :success
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,120 @@
1
+ require 'open-uri'
2
+ require 'nokogiri'
3
+
4
+ module Silkedit::Cheat
5
+ module SilksongJournaler
6
+ @enemylist = YAML.safe_load_file(File.join(Silkedit::LIBDIR, 'config', 'silksong', 'enemylist.yaml'), symbolize_names: false)
7
+
8
+ def update_journal(should_update_kills_only: true)
9
+ enemylist = Silkedit::Cheat::SilksongJournaler.module_eval { @enemylist }
10
+ Rbcli.log.info 'Applying ', 'JOURNAL'
11
+ enemylist['playerData']['EnemyJournalKillData']['list'].sort_by { |known_enemy| known_enemy['Position']}.each do |known_enemy|
12
+ sleep 0.01
13
+ player_enemy = @data['playerData']['EnemyJournalKillData']['list'].find { |i| i['Name'] == known_enemy['Name'] }
14
+ self.display_enemy(known_enemy, player_enemy, show_images: false)
15
+ if player_enemy.nil?
16
+ if should_update_kills_only
17
+ Rbcli.log.info " Not Seen. Skipping.".colorize(:grey)
18
+ else
19
+ new_entry = {
20
+ 'Name' => known_enemy['Name'],
21
+ 'Record' => {
22
+ 'Kills' => known_enemy['Record']['Kills'],
23
+ 'HasBeenSeen' => false
24
+ } }
25
+ @data['playerData']['EnemyJournalKillData']['list'].append(new_entry)
26
+ Rbcli.log.info " Added to journal.".colorize(:magenta)
27
+ end
28
+ elsif player_enemy['Record']['Kills'] < known_enemy['Record']['Kills']
29
+ next if (known_enemy['Record']['Kills'] < 10) && !Silkedit::Sys.yes_no?(" Set #{known_enemy['GameName'].colorize(:blue)} kills from #{player_enemy['Record']['Kills'].to_s.colorize(:red)} to #{known_enemy['Record']['Kills'].to_s.colorize(:green)}?")
30
+ player_enemy['Record']['Kills'] = known_enemy['Record']['Kills']
31
+ player_enemy['Record']['HasBeenSeen'] = true
32
+ Rbcli.log.info " Updated kills.".colorize(:cyan)
33
+ else
34
+ Rbcli.log.info " Already Completed.".colorize(:green)
35
+ end
36
+ end
37
+ end
38
+
39
+ def enemy_list(only_missing: false, show_images: false)
40
+ enemylist = Silkedit::Cheat::SilksongJournaler.module_eval { @enemylist }
41
+ enemylist['playerData']['EnemyJournalKillData']['list'].sort_by { |known_enemy| known_enemy['Position']}.each do |known_enemy|
42
+ player_enemy = @data['playerData']['EnemyJournalKillData']['list'].find { |i| i['Name'] == known_enemy['Name'] }
43
+ left = player_enemy.nil? ? known_enemy['Record']['Kills'] : known_enemy['Record']['Kills'] - player_enemy['Record']['Kills']
44
+ left = 0 if left < 0
45
+ next if only_missing && left <= 0
46
+ self.display_enemy(known_enemy, player_enemy, show_images: show_images)
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def display_enemy(known_enemy, player_enemy, show_images: false)
53
+ self.show_enemy_image(known_enemy['GameName']) if show_images
54
+ left = player_enemy.nil? ? known_enemy['Record']['Kills'] : known_enemy['Record']['Kills'] - player_enemy['Record']['Kills']
55
+ left = 0 if left < 0
56
+ e_complete = left <= 0 ? '*'.colorize(:cyan) : ' '
57
+ e_number = known_enemy['Position'].to_s.rjust(3)
58
+ e_name = known_enemy['GameName'].ljust(27).colorize(:blue).bold
59
+ e_seen = player_enemy.nil? ? 'N'.colorize(:red) : 'Y'.colorize(:green)
60
+ e_kills = (player_enemy.nil? ? 0 : player_enemy['Record']['Kills']).to_s.rjust(4).colorize(:green)
61
+ e_req = known_enemy['Record']['Kills'].to_s.rjust(4).colorize(:blue)
62
+ e_need = left.to_s.rjust(4).colorize(left <= 0 ? :cyan : :red)
63
+ Rbcli.log.info "#{e_number}. #{e_complete} #{e_name} Seen? #{e_seen} Kills: #{e_kills} Needed: #{e_req} Left: #{e_need}"
64
+ end
65
+
66
+ def show_enemy_image(name)
67
+ `which imgcat > /dev/null 2>&1`
68
+ return false unless $?.success?
69
+ enemy_name = name.gsub(' ', '_')
70
+ # enemy_image_directory = File.expand_path(Rbcli::Warehouse.get(:config, :parsedopts)[:images_directory])
71
+ enemy_image_directory = File.join(Silkedit::LIBDIR, 'images', 'silksong')
72
+ cached_image_option_1 = File.join(enemy_image_directory, "#{enemy_name}.png")
73
+ cached_image_option_2 = File.join(enemy_image_directory, "#{enemy_name}_(Silksong).png")
74
+
75
+ command = "imgcat '%s'"
76
+
77
+ if File.exist?(cached_image_option_1)
78
+ system(format(command, cached_image_option_1))
79
+ elsif File.exist?(cached_image_option_2)
80
+ system(format(command, cached_image_option_2))
81
+ else
82
+ got_image = self.get_large_enemy_image(enemy_name, cached_image_option_1)
83
+ got_image = self.get_large_enemy_image("#{enemy_name}_(Silksong)", cached_image_option_2) unless got_image
84
+ show_enemy_image(name) if got_image
85
+ end
86
+ end
87
+
88
+ def get_large_enemy_image(enemy_name, desired_filename)
89
+ begin
90
+ page_url = "https://hollowknight.wiki/w/#{enemy_name}"
91
+ html = URI.open(page_url, 'User-Agent' => 'Ruby/Nokogiri').read
92
+ doc = Nokogiri::HTML(html)
93
+ img = doc.at_css('img.pi-image-thumbnail')
94
+ return false unless img
95
+
96
+ raw = img['src'] || img['data-src'] || img['srcset']
97
+ return false unless raw && !raw.strip.empty?
98
+
99
+ raw = raw.split(',').first.split(/\s+/).first
100
+ image_url = if raw.start_with?('//')
101
+ "https:#{raw}"
102
+ elsif raw =~ %r{\Ahttps?://}
103
+ raw
104
+ else
105
+ URI.join(page_url, raw).to_s
106
+ end
107
+ URI.open(image_url, 'rb', 'User-Agent' => 'Ruby/Nokogiri') do |image_io|
108
+ FileUtils.mkdir_p(File.dirname(desired_filename)) unless File.directory?(File.dirname(desired_filename))
109
+ File.open(desired_filename, 'wb') do |file|
110
+ IO.copy_stream(image_io, file)
111
+ end
112
+ end
113
+ return true
114
+ rescue StandardError => _e
115
+ return false
116
+ end
117
+ end
118
+
119
+ end
120
+ end
@@ -0,0 +1,98 @@
1
+ module Silkedit::Cheat
2
+ module SilksongZoner
3
+ @zonedata = YAML.safe_load_file(File.join(Silkedit::LIBDIR, 'config', 'silksong', 'zones.yaml'), symbolize_names: false)
4
+ @shortcuts = @zonedata['_shortcuts']
5
+ @zonelist = @zonedata.reject { |k, _v| k.start_with?('_') }.to_a.map do |region, r_values|
6
+ r_values.map do |spawnpoint, data|
7
+ {
8
+ "slug" => "#{region}.#{spawnpoint}",
9
+ "shortcut" => @shortcuts.values.include?("#{region}.#{spawnpoint}") ? @shortcuts.key("#{region}.#{spawnpoint}") : nil
10
+ }.merge(data)
11
+ end
12
+ end.flatten
13
+
14
+ def list_zones
15
+ zonelist = Silkedit::Cheat::SilksongZoner.module_eval { @zonelist }
16
+ zonelist.map { |z| z.select { |k, _v| %w[slug shortcut min_act].include?(k) }.transform_keys(&:to_sym) }
17
+ end
18
+
19
+ def list_shortcuts
20
+ Silkedit::Cheat::SilksongZoner.module_eval { @shortcuts }
21
+ end
22
+
23
+ def zone_to(zone, force_soft_reqs: false, enforce_min_act: true)
24
+ zonedata = Silkedit::Cheat::SilksongZoner.module_eval { @zonedata }
25
+ zonelist = Silkedit::Cheat::SilksongZoner.module_eval { @zonelist }
26
+ shortcuts = Silkedit::Cheat::SilksongZoner.module_eval { @shortcuts }
27
+ Rbcli.log.info "Zoning to #{zone}", 'ZONER'
28
+ return self.zone_to(shortcuts[zone], force_soft_reqs: force_soft_reqs, enforce_min_act: enforce_min_act) if shortcuts.key?(zone)
29
+ return :no_zone unless zonelist.find { |z| z['slug'] == zone }
30
+ region, target = zone.split('.')
31
+ Silkedit::Cheat.merge_cheat(
32
+ @data,
33
+ zonedata[region][target],
34
+ should_merge_arrays: true,
35
+ force_soft_reqs: force_soft_reqs,
36
+ enforce_min_act: enforce_min_act
37
+ )
38
+ end
39
+
40
+ def save_current_zone(name, shortcut = nil, act_override = nil, overwrite: false)
41
+ region, target = name.downcase.split('.')
42
+ return :badname unless region && target
43
+ return :badact if !act_override.nil? && (act_override < 1 || act_override > 3)
44
+ return :badshortcut if !shortcut.nil? && shortcut.include?('.')
45
+
46
+ zone = {
47
+ 'data' => {
48
+ 'playerData' => {
49
+ 'atBench' => @data['playerData']['atBench'],
50
+ 'respawnScene' => @data['playerData']['respawnScene'],
51
+ 'mapZone' => @data['playerData']['mapZone'],
52
+ 'extraRestZone' => @data['playerData']['extraRestZone'],
53
+ 'respawnMarkerName' => @data['playerData']['respawnMarkerName'],
54
+ 'respawnType' => @data['playerData']['respawnType'],
55
+ 'hazardRespawnFacing' => @data['playerData']['hazardRespawnFacing'],
56
+ }
57
+ },
58
+ 'soft_reqs' => {},
59
+ 'hard_reqs' => {},
60
+ 'min_act' => act_override || Silkedit::Cheat.get_game_act(@data)
61
+ }
62
+
63
+ rosarylock = @data['sceneData']['persistentBools']['serializedList'].find { |i| i['SceneName'] == @data['playerData']['respawnScene'] && i['ID'] == 'bell_toll_machine' }
64
+ zone['soft_reqs'].merge!({'sceneData' => {'persistentBools' => {'serializedList' => [rosarylock]}}}) unless rosarylock.nil?
65
+ leverlock = @data['sceneData']['persistentInts']['serializedList'].find { |i| i['SceneName'] == @data['playerData']['respawnScene'] && i['ID'].include?('Bellshrine Sequence') }
66
+ zone['soft_reqs'].merge!({'sceneData' => {'persistentInts' => {'serializedList' => [leverlock]}}}) unless leverlock.nil?
67
+
68
+ zonedata = Silkedit::Cheat::SilksongZoner.module_eval { @zonedata }
69
+ zonelist = Silkedit::Cheat::SilksongZoner.module_eval { @zonelist }
70
+ known_zone_idx = zonelist.find_index do |known_zone|
71
+ known_zone['data']['playerData']['respawnScene'] == zone['data']['playerData']['respawnScene'] &&
72
+ known_zone['data']['playerData']['respawnMarkerName'] == zone['data']['playerData']['respawnMarkerName']
73
+ end
74
+
75
+ if known_zone_idx
76
+ if overwrite
77
+ old_region, old_target = zonelist[known_zone_idx]['slug'].split('.')
78
+ zonedata[old_region].delete(old_target)
79
+ zonedata.delete(old_region) if zonedata[old_region].empty?
80
+ else
81
+ return zonelist[known_zone_idx]['slug']
82
+ end
83
+ end
84
+
85
+ zonedata[region] ||= {}
86
+ zonedata[region][target] = zone
87
+ zonedata[region] = zonedata[region].sort_by { |k, _v| k }.to_h
88
+ zonedata = zonedata.sort_by { |k, _v| k }.to_h
89
+
90
+ if shortcut
91
+ zonedata['_shortcuts'][shortcut] = "#{region}.#{target}"
92
+ end
93
+
94
+ File.write(File.join(Silkedit::LIBDIR, 'config', 'silksong', 'zones.yaml'), YAML.safe_dump(zonedata))
95
+ :success
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,13 @@
1
+ ---
2
+ savegame_directory:
3
+ hollow_knight:
4
+ macos: '~/Library/Application Support/unity.Team Cherry.Hollow Knight'
5
+ linux: '~/.config/unity3d/Team Cherry/Hollow Knight'
6
+ windows: '%UserProfile%\AppData\LocalLow\Team Cherry\Hollow Knight'
7
+ silksong:
8
+ macos: '~/Library/Application Support/unity.Team-Cherry.Silksong/%STEAMID%'
9
+ linux: '~/.config/unity3d/Team Cherry/Hollow Knight Silksong/%STEAMID%'
10
+ windows: '%USERPROFILE%/AppData/LocalLow/Team Cherry/Hollow Knight Silksong/%STEAMID%'
11
+ max_backups: 5
12
+ use_yaml: true
13
+ aes_key: 'UKu52ePUBwetZ9wNX88o54dnfKRu0T1l'
@@ -0,0 +1,6 @@
1
+ ---
2
+ editor_command: vi '%FILE%'
3
+ permasave_file_location:
4
+ macos: '~/.silkedit.yaml'
5
+ linux: '~/.silkedit.yaml'
6
+ windows: '%APPDATA%\silkedit\silkedit.yaml'