Closed DeviateFish closed 1 month ago
Lot to think of :D If you have Discord it would be easier to discuss all that. Not against PR, but some times they take more time for me to handle than keeping things in order.
Yeah, I can definitely pop into Discord in the near future. It'll probably be in a couple days or so, since I'm currently away from home. What's your timezone, and when do you think you'd be most available to chat?
I did a little more digging and it doesn't seem like there's really a good pure-JS option for creating a timelapse from individual frames, especially if you want to do something fancy like have variable input framerates. I think variable framerates is probably a must, since I think it would make the most sense to have the playback be x seconds per hour of playtime
or something like that. Since there's no good guarantee that each save in a set of files will be created at a regular interval (like every hour or something), it would probably be best to accommodate for uneven intervals from the start. Most examples of creating videos from frames in js seem to just delegate to ffmpeg
to get the job done, which is... probably the right call, honestly. This does limit them to being server-side only, which introduces its own set of complications.
The "good news" is that this means any changes here could be limited to those needed to support the generation of a single static image per save game (and maybe some JSON metadata for timing purposes?), and whatever scaffolding is required to make that friendly to automation. I've done automated frame capture in the browser before (aside: I see we both like FileSaver.js
😄) with decent results (see below), but it's kind of janky, and would still require some changes to where the lines of abstraction currently lie.
Given a list of images generated from a list of save games and some information about how much playtime had elapsed for each snapshot, the process of creating the timelapse can be entirely independent and happen in any environment.
So after sleeping on this, I realized that the most basic MVP would essentially just be the ability to export a screenshot of the map after loading a save file. Technically, everything else that needs to be done to create the timelapse can be done outside the tool, even if it requires a bunch of manual work. Some of it probably has to happen outside the tool, especially if things like ffmpeg
are requried.
My preference would still be to automate it, or be able to use parts of your codebase as a library to do so, but from the perspective of introducing a minimal set of changes to the thing you've built, I think just exporting a screenshot would be sufficient.
It looks like several options exist as Leaflet plugins to do this, so it might be pretty straightforward. Some of them look like they have some caveats (some kinds of markers aren't supported since they're html and not drawn directly in the canvas
element, etc), but for at least my purposes, that's an acceptable limitation.
If none of those plugins work, I think it would be possible to do manually by:
Obviously being able to automate the above and manipulate the canvas itself (setting zoom and canvas size, for example) for multiple save games would be more ideal, but I'd definitely be able to accomplish what I want with just the above and some additional scripts (either Tampermonkey or cli) to extract the header information from each save to get the playtime information.
I'll edit the title of the issue to better reflect this, and we can still chat on Discord about this tomorrow, but I wanted to get this down in writing so I don't forget 😄
@DeviateFish
Is this possible to even do in the browser?
past experience says yes
"list of frames for a timelapse" (or video/gif)
see #35
Most examples of creating videos from frames in js seem to just delegate to ffmpeg to get the job done
see https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/captureStream and https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder
see https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/captureStream and https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder
Oh that's pretty nifty. Also, thanks for linking the old issue, it seems I'm definitely not the only one who has had this idea.
I'm still not entirely sure the browser is indeed the right place to do this, though. My biggest concern is the memory limitations, since it looks like the save files can get pretty big, and that's in a compressed format. I also didn't really think of doing timelapses for specific areas of the map (as opposed to just the entire map over time), so I can see that being a slightly different use-case. One is just a superset of the other, so it definitely could be built to do so. Being able to easily control the viewpoint is certainly a point in favor of doing it natively in the browser, however.
I'll take a peek at the linked APIs and see if I can cobble something together.
Fair warning though: I have no intention of doing anything here that could compete with anything @AnthorNet has built, so whether or not any of the stuff I end up building makes it into main
is entirely up to them. I'll certainly be sharing my results with them, but I won't be releasing anything publicly without express consent 😄
@DeviateFish it may be more practical to knock up a standalone CLI tool that uses https://github.com/puppeteer/puppeteer
@DeviateFish it may be more practical to knock up a standalone CLI tool that uses https://github.com/puppeteer/puppeteer
I had considered that, but I really hate puppeteer. It might be the least worst option out of all the browser orchestration tools, but it's still bad. Using a headless browser is probably going to be my last resort, rather than first 😄
@AnthorNet 🤔 I just had a terrible idea
Let me preface this by saying that I really enjoy the work you've done here, and think you've built a wonderful tool for the Satisfactory community. I use the interactive map almost every time I play, to figure out where to build, to sanity check the inputs/outputs of factories. I haven't yet dabbled in any of the more advanced features, like editing save files, but it looks like quite the suite of features.
Using this tool has given me an idea. I have a proposal for a new feature, one that I'd like to implement if I get your approval.
I would like to be able to provide the tool (or a new tool) with a whole list of save games, and have it generate a timelapse of the whole map across all those saves. I think this would be a really cool way to look back on the history of a particular Satisfactory playthrough, to see how factories and setups evolve over time. The quality of the timelapse would obvious depend heavily on the saves themselves, but I think it could produce some really cool results, especially for people who regularly produce Satisfactory content.
This is a huge feature. So far, from browsing through the codebase, looking at the save file parsing, and looking at the supporting libraries, some big concerns arise:
Leaflet
canvas multiple times over, meaning all the code that changes the UI would probably need to be decoupled from the map generating code. This doesn't seem particularly hard, but it would require a very large number of small changes.Leaflet
makes a lot of assumptions about being run in the browser environment, and there doesn't seem to be any current plan to change that. This isn't an insurmountable problem, but would involve reaching into the internals ofLeaflet
and shimming out quite a number of things. This can probably be done with some combination of that and something likenode-canvas
, so this seems like a surmountable challenge. I've definitely pulled off these sorts of shimming things in the past, so it's definitely possible.Given all the above, this seems like a pretty big project, but I do think it can be broken down into a set of smaller projects that each are more tractable:
Leaflet
) code out ofGameMap
and into a separate class that is controlled byGameMap
. This would letGameMap
still render everything it needs, while also manipulating the UI as it currently does, while also letting the new component class be used independently.BaseLayout
which also directly manipulates a number of UI elements.Leaflet
reference, instead of depending on theL
globalSome other questions/concerns:
Leaflet
reference would actually make this pretty straightforward in many cases, since assertions can be made that certain markers are created/destroyed/modified, etc() => {}
... andfunction() {}.bind(this)
, which could be standardized to the former in (almost?) all cases. If this is a welcome cleanup, it could function as a good decent "first issue"; if it's not a welcome change, I can obviously leave it alone entirely.Thoughts? Questions? I'd really like to make this a reality. I also know that this is your project, and I don't want to intrude or impose in any way. I think what you've built is pretty incredible, which is why I would love to use it as a starting point for this particular project. I could in theory build all the requisite pieces from scratch, drawing on your work for inspiration, but I think in many ways that would be a disservice to the work you've done here. You've also made it pretty clear that this is your code, and that it's not to be used for any external purposes. I would like to respect that.