{"id":1120,"date":"2015-12-20T16:04:58","date_gmt":"2015-12-20T21:04:58","guid":{"rendered":"http:\/\/www.bootdiskrevolution.com\/?p=1120"},"modified":"2016-02-28T13:37:04","modified_gmt":"2016-02-28T18:37:04","slug":"replays2","status":"publish","type":"post","link":"https:\/\/www.bootdiskrevolution.com\/NEW_BLOG\/replays2\/","title":{"rendered":"Replays 2: Replay&#8217;s Revenge"},"content":{"rendered":"<p>Last week I said I needed a vacation, and I almost took one! Instead, I worked on something I find infinitely exciting &#8212; implementing a replay system in Bleed 2! This will be a continuation of <a href=\"http:\/\/www.bootdiskrevolution.com\/replays\/\">the replays post I made a few months back<\/a>. It will also be very wordy, sorry about that!<\/p>\n<p>&nbsp;<\/p>\n<h4 style=\"text-align: center;\">Implementing Replays<\/h4>\n<p>A quick refresher: I&#8217;m storing the user&#8217;s inputs every frame and saving them in a file. When it comes time to watch a replay, the game uses the saved inputs to reproduce the playthrough. I call each frame of input ReplayData.<\/p>\n<p>I need to make sure there&#8217;s no difference between the player controlling Wryn and a replay file controlling her. So, even when you play the game your inputs are converted into ReplayData before they go to Wryn. When you watch a replay, the ReplayData comes from the recorded file instead of the player. Either way, Wryn is getting the exact same kind of information at the exact same time.<\/p>\n<figure id=\"attachment_1126\" aria-describedby=\"caption-attachment-1126\" style=\"width: 512px\" class=\"wp-caption aligncenter\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"wp-image-1126\" src=\"https:\/\/i0.wp.com\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-content\/uploads\/2015\/12\/playerInput.png?resize=512%2C347\" alt=\"\" width=\"512\" height=\"347\" srcset=\"https:\/\/i0.wp.com\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-content\/uploads\/2015\/12\/playerInput.png?w=640&amp;ssl=1 640w, https:\/\/i0.wp.com\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-content\/uploads\/2015\/12\/playerInput.png?resize=300%2C203&amp;ssl=1 300w\" sizes=\"auto, (max-width: 512px) 100vw, 512px\" \/><figcaption id=\"caption-attachment-1126\" class=\"wp-caption-text\">Highly technical diagram of the two ways Wryn can receive ReplayData<\/figcaption><\/figure>\n<h4 style=\"text-align: center;\"><\/h4>\n<p>&nbsp;<\/p>\n<h4 style=\"text-align: center;\">Problems<\/h4>\n<p>Once I re-coded everything to work this way, I started running into problems. A big one was handling menus &#8212; menus aren&#8217;t part of replay files so they aren&#8217;t controlled by ReplayData, and ReplayData isn&#8217;t created while they are active.<\/p>\n<p>An example of when this is an issue: the game is paused. You select &#8216;return to game&#8217; by pressing the jump button. You weren&#8217;t pressing the jump button before you paused, and since Wryn hasn&#8217;t gotten any new ReplayData since then, as far as she knows the jump button is up. As soon as you un-pause, fresh ReplayData is created telling her the jump button is now down, causing Wryn to jump or air-dash when you didn&#8217;t intend her to.<\/p>\n<p><!--more--><\/p>\n<p>The solution was to add another bool (a true\/false flag) to the ReplayData, letting Wryn know if she was just in a menu so she can ignore jump button presses immediately after resuming play. The bool has to be stored in the ReplayData &#8212; if it was just part of the pause menu, you could mess up playback by pausing\/un-pausing during replays.<\/p>\n<figure id=\"attachment_1125\" aria-describedby=\"caption-attachment-1125\" style=\"width: 512px\" class=\"wp-caption aligncenter\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"wp-image-1125\" src=\"https:\/\/i0.wp.com\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-content\/uploads\/2015\/12\/oldData.png?resize=512%2C512\" alt=\"\" width=\"512\" height=\"512\" srcset=\"https:\/\/i0.wp.com\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-content\/uploads\/2015\/12\/oldData.png?w=640&amp;ssl=1 640w, https:\/\/i0.wp.com\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-content\/uploads\/2015\/12\/oldData.png?resize=150%2C150&amp;ssl=1 150w, https:\/\/i0.wp.com\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-content\/uploads\/2015\/12\/oldData.png?resize=300%2C300&amp;ssl=1 300w\" sizes=\"auto, (max-width: 512px) 100vw, 512px\" \/><figcaption id=\"caption-attachment-1125\" class=\"wp-caption-text\">This is what a frame of ReplayData looked like after the fix.<\/figcaption><\/figure>\n<h4 style=\"text-align: center;\"><\/h4>\n<p>&nbsp;<\/p>\n<h4 style=\"text-align: center;\">Optimizing Stored Inputs<\/h4>\n<p>This created another problem &#8212; the additional bool means every frame of ReplayData takes up about 10% more space. I want to keep replay files as small as possible, and this is where my wonderful coder father came in with some slick optimizations.<\/p>\n<p>This is a bit technical, and I can only explain it as well as I understand it, but here goes:<\/p>\n<p>Everything in code takes up bytes of memory. So, in my ReplayData: the bool for &#8220;<em>is the jump button down?&#8221;<\/em> uses one byte. The bool for &#8220;<em>was the player just using the menu?&#8221; <\/em>uses another byte. Every true\/false value I store takes up another byte in memory.<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-761\" src=\"https:\/\/i0.wp.com\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-content\/uploads\/2015\/06\/screenie1.png?resize=640%2C360\" alt=\"\" width=\"640\" height=\"360\" srcset=\"https:\/\/i0.wp.com\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-content\/uploads\/2015\/06\/screenie1.png?w=800&amp;ssl=1 800w, https:\/\/i0.wp.com\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-content\/uploads\/2015\/06\/screenie1.png?resize=300%2C169&amp;ssl=1 300w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/p>\n<p>Now here&#8217;s a secret: a byte is actually made up of 8 smaller units, called bits. Bits are super simple: they can only be 0 or 1. So for example:<\/p>\n<p>A byte storing the number 1, in bits, is: 00000001<br \/>\nA byte storing the number 20, in bits, is: 00010100<br \/>\nAnd so on. They&#8217;re all eight 0&#8217;s and 1&#8217;s, in different combinations!<\/p>\n<p>What does all this have to do with anything? Well, I&#8217;ve got a lot of bools taking up space in my ReplayData. If you&#8217;ll notice, a bool is just a value holding true\/false, which is kind of like&#8230; a bit, that only holds 0\/1?<\/p>\n<p>Yes! So if you know what you&#8217;re doing (as my pops does) you can use the 8 bits in a single byte to act as 8 true\/false flags! So instead of my ReplayData using 4 bools (one byte each), I now have one byte to store them all, which even leaves 4 bits left over if I ever need more flags!<\/p>\n<figure id=\"attachment_1124\" aria-describedby=\"caption-attachment-1124\" style=\"width: 512px\" class=\"wp-caption aligncenter\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"wp-image-1124\" src=\"https:\/\/i0.wp.com\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-content\/uploads\/2015\/12\/newData.png?resize=512%2C346\" alt=\"\" width=\"512\" height=\"346\" srcset=\"https:\/\/i0.wp.com\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-content\/uploads\/2015\/12\/newData.png?w=640&amp;ssl=1 640w, https:\/\/i0.wp.com\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-content\/uploads\/2015\/12\/newData.png?resize=300%2C203&amp;ssl=1 300w\" sizes=\"auto, (max-width: 512px) 100vw, 512px\" \/><figcaption id=\"caption-attachment-1124\" class=\"wp-caption-text\">The new, ultra-compressed ReplayData!<\/figcaption><\/figure>\n<p>Before, every frame of ReplayData was 10 bytes &#8212; now it&#8217;s 7! Worst case, even an hour-long co-op replay will only use 3Mb, where before it would take almost 4.5Mb! I really like these numbers.<\/p>\n<h4 style=\"text-align: center;\"><\/h4>\n<p>&nbsp;<\/p>\n<h4 style=\"text-align: center;\">The End (For Now&#8230;)<\/h4>\n<p>Soooooo yeah! That&#8217;s what I did this week! It was kind of a break from usual work, but still potentially helped the game! Replays aren&#8217;t fully working yet, and they aren&#8217;t tested at all, but they&#8217;re starting to get in there and things seem promising for now, so I&#8217;m excited!<\/p>\n<p>If you made it all the way to the end, thank you for reading! I hope maybe you learned something! Here&#8217;s a shot of the replays in action to close things out.<\/p>\n<figure id=\"attachment_1122\" aria-describedby=\"caption-attachment-1122\" style=\"width: 512px\" class=\"wp-caption aligncenter\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"wp-image-1122\" src=\"https:\/\/i0.wp.com\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-content\/uploads\/2015\/12\/IRLgif_final_O.gif?resize=512%2C274\" alt=\"\" width=\"512\" height=\"274\" \/><figcaption id=\"caption-attachment-1122\" class=\"wp-caption-text\">Yeah, I understand I could have faked this with a pre-recorded video, but please take my word for it. The game is replaying my inputs back to me!<\/figcaption><\/figure>\n<p>NOW I&#8217;m on vacation for real. Peace!!<\/p>\n<p><a href=\"http:\/\/www.bootdiskrevolution.com\/replays3\/\">Update: More replay work is detailed in this post.<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last week I said I needed a vacation, and I almost took one! Instead, I worked on something I find infinitely exciting &#8212; implementing a replay system in Bleed 2! This will be a continuation of the replays post I made a few months back. It will also be very wordy, sorry about that! &nbsp; <a class=\"read-more\" href=\"https:\/\/www.bootdiskrevolution.com\/NEW_BLOG\/replays2\/\">[&hellip;]<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[6],"tags":[],"class_list":["post-1120","post","type-post","status-publish","format-standard","hentry","category-bleed-2"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-json\/wp\/v2\/posts\/1120","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-json\/wp\/v2\/comments?post=1120"}],"version-history":[{"count":15,"href":"https:\/\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-json\/wp\/v2\/posts\/1120\/revisions"}],"predecessor-version":[{"id":1273,"href":"https:\/\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-json\/wp\/v2\/posts\/1120\/revisions\/1273"}],"wp:attachment":[{"href":"https:\/\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-json\/wp\/v2\/media?parent=1120"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-json\/wp\/v2\/categories?post=1120"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.bootdiskrevolution.com\/NEW_BLOG\/wp-json\/wp\/v2\/tags?post=1120"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}