<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>joelschumacher.de Blog</title>
    <link href="https://joelschumacher.de/blog"/>
    <link rel="self" href="https://joelschumacher.de/blog/atom.xml"/>
    <updated>2025-02-07T20:03:00+0000</updated>
    <id>https://joelschumacher.de/blog</id>
    <author>
        <name>Joel Schumacher</name>
    </author>

    
    <entry>
        <title>Stop Overcomplicating Parsing</title>
        
        <link href="https://joelschumacher.de/posts/stop-overcomplicating-parsing"/>
        <id>https://joelschumacher.de/posts/stop-overcomplicating-parsing</id>
        <updated>2025-02-07T20:03:00+0000</updated>
        <content type="html">&amp;lt;h2 id="introduction"&amp;gt;Introduction&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;I have been working on a little programming language for the last couple of days and the software and theory around parsing is just eternally frustrating. People have built mind-boggling theory temples around this and I think nothing attracts architecture astronauts like parsing. I not convinced that most of it is not necessary and it is not actually this difficult.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;You read about &amp;lt;code&amp;gt;LL(k)&amp;lt;/code&amp;gt; parsers, &amp;lt;code&amp;gt;LL(*)&amp;lt;/code&amp;gt; parsers, &amp;lt;code&amp;gt;LL(1)&amp;lt;/code&amp;gt; parsers, &amp;lt;code&amp;gt;LR(k)&amp;lt;/code&amp;gt; parsers, &amp;lt;code&amp;gt;LALR&amp;lt;/code&amp;gt; parsers, &amp;lt;code&amp;gt;SLR&amp;lt;/code&amp;gt; parsers, &amp;lt;code&amp;gt;GLR&amp;lt;/code&amp;gt; parsers, Earley parsers (all of these are real) and more. It makes your head spin and barf all the &amp;lt;code&amp;gt;LOL(k)&amp;lt;/code&amp;gt; parsers right back onto the screen. I keep thinking &amp;amp;ldquo;no one cares dude, just parse the thing&amp;amp;rdquo;.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;We haven&amp;amp;rsquo;t just lost bright minds to parsing theory, but (the real tragedy) countless of people have been discouraged to parse something by the overwhelming overcomplication of the subject.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;It&amp;amp;rsquo;s so silly to me that people that know nothing about parsing just parse stuff with recursive descent parsers and when you go to the really complicated languages and the really large parsers (JavaScript V8, TypeScript, Rust, CPython, GCC), you end up having to use recursive descent again. It&amp;amp;rsquo;s kind of weird there is a whole science inbetween. Maybe the stuff in the middle is not really that useful?&amp;lt;/p&amp;gt;
&amp;lt;h2 id="recursive-descent"&amp;gt;Recursive Descent&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;For everyone who doesn&amp;amp;rsquo;t know much about parsing: A recursive descent parser is just the thing you would write down if you didn&amp;amp;rsquo;t know anything about parsing.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Consider this simple grammar (&amp;lt;a href="https://de.wikipedia.org/wiki/Erweiterte_Backus-Naur-Form"&amp;gt;EBNF&amp;lt;/a&amp;gt;-like):&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;none
action: ("run" | "stop") (flag | arg)*
flag: "--verbose" | "--force"
arg: WORD&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;which defines a language that has &amp;lt;code&amp;gt;action&amp;lt;/code&amp;gt;s, which start either with &amp;lt;code&amp;gt;"run"&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;"stop"&amp;lt;/code&amp;gt; and are followed by any number of &amp;lt;code&amp;gt;flag&amp;lt;/code&amp;gt;s or &amp;lt;code&amp;gt;arg&amp;lt;/code&amp;gt;s. &amp;lt;code&amp;gt;flag&amp;lt;/code&amp;gt; can either be &amp;lt;code&amp;gt;--verbose&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;--force&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;arg&amp;lt;/code&amp;gt; must be a &amp;lt;code&amp;gt;WORD&amp;lt;/code&amp;gt; (whatever that is, it doesn&amp;amp;rsquo;t matter). You would just write it with each rule being a function, sequences just being code after other code and choices (&amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;) being an &amp;lt;code&amp;gt;if/else&amp;lt;/code&amp;gt;:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;```python
def parse_action(parser):
  action = Action()
  parser.skip_whitespace()
  if parser.input.startswith(&amp;amp;ldquo;run&amp;amp;rdquo;):
    action.verb = &amp;amp;ldquo;run&amp;amp;rdquo;
  elif parser.input.startswith(&amp;amp;ldquo;stop&amp;amp;rdquo;):
    action.verb = &amp;amp;ldquo;stop&amp;amp;rdquo;
  else:
    return None&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;while parser.has_input():
    parser.skip_whitespace()
    flag = parse_flag(parser)
    if flag:
      action.flags.append(flag)
      continue
      arg = parse_arg(parser)
    if arg:
      action.args.append(arg)
  return action
```&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Ignore some &amp;lt;code&amp;gt;parser.skip_whitespace()&amp;lt;/code&amp;gt; I might have missed and pretend &amp;lt;code&amp;gt;parse_flag&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;parse_arg&amp;lt;/code&amp;gt; look mostly like that. You don&amp;amp;rsquo;t even have to think much when you write a parser like that.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;There is no science here. You are just writing it out. And I didn&amp;amp;rsquo;t even need a &amp;lt;code&amp;gt;ROFL(69)&amp;lt;/code&amp;gt; parser or whatever. If you don&amp;amp;rsquo;t know anything and are humble enough, you might think &amp;amp;ldquo;but maybe this is slow&amp;amp;rdquo; (because it&amp;amp;rsquo;s dumb/straightforward), but no, recursive descent is often one of the fastest ways to parse things.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Maybe there are languages / grammars you can&amp;amp;rsquo;t parse with it? No, not even that. Recursive descent is one of the only popular algorithms that can parse context sensitive languages.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Other parsers have problems with error recovery (mostly a meme as well btw. - &amp;lt;a href="#error-recovery"&amp;gt;see below&amp;lt;/a&amp;gt;) or with reporting good error messages. Even that is trivial with recursive descent parsers.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;And they are also comparatively easy to debug.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;It can do more, it can do it faster, it can do it better, it can do it easier. What the hell is everyone doing?&amp;lt;/p&amp;gt;
&amp;lt;h3 id="expressions"&amp;gt;Expressions&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;The actual real downside of recursive descent parsers is parsing expressions. You can do it, but encoding operator precedence is tricky and non-intuitive (you need a separate parsing function for each precedence level). And if you do it that way, it tends to do a lot of backtracking, which ends up being slow (worst case exponential time - blegh).&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;People have come up with &amp;lt;a href="https://en.wikipedia.org/wiki/Packrat_parser"&amp;gt;packrat parsing&amp;lt;/a&amp;gt;, which caches some of the intermediate results during parsing, which reduces it to linear time, but this honestly also makes my &amp;amp;ldquo;overcomplication&amp;amp;rdquo; senses tingle.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The cool thing about recursive descent is that it is so ad-hoc that you can easily combine it with other algorithms, for example algorithms that are made specifically to parse expressions with different operators that have different precedence levels. One of the best (and coolest) algorithms to do this is &amp;amp;ldquo;&amp;lt;a href="https://en.wikipedia.org/wiki/Operator-precedence_parser#Pratt_parsing"&amp;gt;Pratt parsing&amp;lt;/a&amp;gt;&amp;amp;rdquo; (I recommend this blog post: &amp;lt;a href="https://eli.thegreenplace.net/2010/01/02/top-down-operator-precedence-parsing"&amp;gt;link&amp;lt;/a&amp;gt;). So if recursive descent is the best for almost anything and Pratt parsing is the best at parsing expressions and you can combine them well, why not just use those two? I wrote a parser for a small language recently in a couple days that does exactly this and it&amp;amp;rsquo;s great. I cannot find a single parser generator that does this and it confuses me to no end.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="actual-downsides"&amp;gt;Actual Downsides&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;The actual problem I am willing to acknowledge is that recursive descent parsers can remove ambiguity from an ambiguous grammar. Ambiguous grammars are grammars which allow that an input is parsed in different ways. This is mostly bad. And if you don&amp;amp;rsquo;t notice that your grammar is ambiguous and write a recursive descent parser for that grammar (which cannot be ambiguous), then you have kept the ambiguity in your grammar hidden and your grammar does not fit to the parser anymore!&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;All the other fancy parsers that get CS students and academics excited have the cool property that you can derive a parser from an unambiguous grammar and if you have an &amp;lt;code&amp;gt;LL/LR&amp;lt;/code&amp;gt; parser or whatever you can derive a grammar from it. Of course recursive descent does not have any nice theoretical properties like that.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;First of all I think it&amp;amp;rsquo;s silly to choose a parser based on whether it helps you find problems with your grammar. If you want, you can use an existing &amp;lt;code&amp;gt;LR&amp;lt;/code&amp;gt; parser to verify that your grammar is unambiguous and then write the recursive descent parser (many people do this).&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;People are rightfully obsessed with removing ambiguities in their grammar, but why not simply come up with a grammar that can&amp;amp;rsquo;t even have them? Like PEG! &amp;lt;a href="https://en.wikipedia.org/wiki/Parsing_expression_grammar"&amp;gt;Parsing Expression Grammars&amp;lt;/a&amp;gt; replace the choice operator (&amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; before) with an ordered choice which implies a priority of the first (left hand side) option and thereby removes ambiguity.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;This is actually sick, because if you notice above I started with checking for &amp;lt;code&amp;gt;run&amp;lt;/code&amp;gt; and then checked for &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt;. The grammar didn&amp;amp;rsquo;t actually imply a priority there, but my code did of course. There might be an expression that can get parsed by both &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt;s after all. And if you use a PEG then those different branches in your code DO have a well-defined, correct order. In that way PEGs map to recursive descent parsers more directly.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Parsing experts don&amp;amp;rsquo;t like them much and I don&amp;amp;rsquo;t really understand why. I read that it&amp;amp;rsquo;s somehow undesirable that PEGs are unambiguous because you can write stuff that looks correct, but actually isn&amp;amp;rsquo;t and no one complains. I think this is mostly (again) related to operator precedence. Also they use more memory, which I respect as a limitation in certain scenarios, but I have 32G of RAM and that&amp;amp;rsquo;s not even a lot, but more than plenty to parse a couple MBs of code.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="theory"&amp;gt;Theory&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;Generally I am all for theory. It&amp;amp;rsquo;s important that someone understand these things (and anything else) on a truly deep level. Someone needs to know what is possible and provable and correct, but what confuses me is the ratio of people doing pragmatic parsing and people swooning over parsing algorithms. I feel like the whole world is tricking me into thinking I actually need a lecture to parse text. I don&amp;amp;rsquo;t - you can literally just parse it.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I acknowledge that there was a time where all this theory was actually necessary to compile C on an analogue toothbrush in some ancient sumerian assembly. And they did develop some great ideas that are useful to this day (like precedence climbing / Pratt parsing), but honestly I think most of this stuff is just not interesting to the majority of people that want to turn text into trees.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="lexing"&amp;gt;Lexing&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;I think everyone is overdoing it on lexing / tokenization. I get what lexing is for, but it also feels like it is mainly to make the parser more elegant, because it can just work on tokens and doesn&amp;amp;rsquo;t have to skip whitespace and comments itself. I am not convinced its actually solving a real problem. The fact alone that plenty of parsers do not lex as a separate step proves this.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;When I see &amp;amp;ldquo;struct&amp;amp;rdquo; in the right place, I &amp;lt;em&amp;gt;know&amp;lt;/em&amp;gt; there has to be an identifier next and if there is not, I should error out right then and there. I don&amp;amp;rsquo;t need to figure out &amp;lt;em&amp;gt;generally&amp;lt;/em&amp;gt; what could be at any point in the text. It feels like I now have to solve two problems (parsing and figuring out what kind of token a string might be without knowing where it is), when I can solve it in one go and effectively have FEWER problems this way.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I heard that lexing separately can actually be faster, because it&amp;amp;rsquo;s cheap to do and it makes parsing simpler, but I heard more often that a &amp;amp;ldquo;scannerless parser&amp;amp;rdquo; (no separate lexing step) is usually faster. And even if having a separate lexing step is slightly faster, I am not convinced it&amp;amp;rsquo;s worth the trouble.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="parse-generators-existing-libraries"&amp;gt;Parse Generators / Existing Libraries&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;When I see YACC/Bison or Lemon all these other things I cannot believe how people started putting C in their grammar. And it&amp;amp;rsquo;s not just regular C, which is bad enough, but stuff like &amp;lt;code&amp;gt;$$ = system__create_ast_node_ternary(auxil, AST_NODE_TYPE_STATEMENT_IF_ELSE, range__new($0s, $0e), e, s, t);&amp;lt;/code&amp;gt;. This is not code, this is garbage. You went the wrong way!&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Why do &amp;lt;em&amp;gt;none&amp;lt;/em&amp;gt; of the popular parser generators just output a damn AST by default? If you write a parser generator, just give me the AST! Don&amp;amp;rsquo;t overdo it, just give me a bunch of these:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;c++
struct Node {
    NodeType type;
    size_t start, end;
    Node* children;
    size_t num_children;
};&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Where is the &amp;amp;ldquo;common man&amp;amp;rdquo; tool/library that accomodates practical parsing needs and is not just for parsing nerds? I don&amp;amp;rsquo;t need your help, if I already know how to do it! Do I have to make one myself? I already don&amp;amp;rsquo;t have enough time.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Honestly more than half the tools I come across I don&amp;amp;rsquo;t even understand! I have been programming for 20 years and done a bunch of different things. I have Bachelor&amp;amp;rsquo;s degree in Physics. I&amp;amp;rsquo;m stupid, but not completely stupid. Parsing text is really not difficult if you do it the right way, but somehow everything out there is super complicated anyways.&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I tried getting a grip on all this stuff multiple times through the years, eventually just gave up after a few hours (until recently) and ended up writing a recursive descent parser again, in the beginning not even knowing that is what they were called.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="expressions_1"&amp;gt;Expressions&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;EVERY LANGUAGE&amp;lt;/em&amp;gt; needs expressions. Why do we have to solve this a million times? Why can&amp;amp;rsquo;t I just define a set of sub-languages with their operators and precedences and the parser will work it out?
If you build a parser generator there should be a built-in feature for operator expressions. What do you think people use your generators for? Everyone needs this.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="what-i-want"&amp;gt;What I Want&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;Like I said I gave up many times on parsing. The first tool that changed my mind was &amp;lt;a href="https://github.com/lark-parser/lark"&amp;gt;lark&amp;lt;/a&amp;gt;. It is so cool in large part because it eats almost any grammar you give it and because it spits out an AST right away, which you can just post-process (or you can customize the AST generation).&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The problem with lark is of course that it&amp;amp;rsquo;s a Python library and I don&amp;amp;rsquo;t want to call into Python to parse (lol). Also it&amp;amp;rsquo;s pretty slow. I wrote a grammar for the language I am working on and it takes about 10 seconds to parse less than 200 lines, which is, of course, absurd.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The thing I want should generate a C parser, because you can integrate those into anything. It should have roughly these features:&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;PEG grammars with sub-grammars for a Pratt parser for expressions&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Generates recursive descent parser (with Pratt sub-parser for expressions)&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Easy way to skip whitespace and comments (you need that almost always - It has to be built-in!)&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Generates AST right away by default&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;p&amp;gt;Something like this (don&amp;amp;rsquo;t hold me to that - I already don&amp;amp;rsquo;t like a bunch of things about this):&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;```
start: assignment&amp;lt;em&amp;gt;
assignment: IDENTIFIER &amp;amp;ldquo;=&amp;amp;rdquo; expr &amp;amp;ldquo;;&amp;amp;rdquo;
expr: {
  primary: IDENTIFIER | NUMBER | &amp;amp;ldquo;(&amp;amp;rdquo; expr &amp;amp;ldquo;)&amp;amp;rdquo;
  prefix &amp;amp;ldquo;-&amp;amp;rdquo; (10): expr
  infix &amp;amp;ldquo;-&amp;amp;rdquo; (1): expr
  infix &amp;amp;ldquo;+&amp;amp;rdquo; (1): expr
  infix &amp;amp;ldquo;&amp;lt;/em&amp;gt;&amp;amp;rdquo; (2): expr
  infix &amp;amp;ldquo;/&amp;amp;rdquo; (2): expr
  infix &amp;amp;ldquo;^&amp;amp;rdquo; right (5): expr
}&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;IDENTIFIER: [a-zA-Z_][a-zA-Z0-9_]&amp;lt;em&amp;gt;
NUMBER: [0-9]+
WS: [ \t\n\r]
COMMENT: &amp;amp;ldquo;#&amp;amp;rdquo; (!&amp;amp;rdquo;\n&amp;amp;rdquo;.)&amp;lt;/em&amp;gt; &amp;amp;ldquo;\n&amp;amp;rdquo;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;!ignore COMMENT WS
```&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I just want to say which operators I have, what operands they take, their binding powers (in parentheses in the example above) and whether they are prefix/infix/postfix and the parser will do the rest.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I feel like a tool like that would be &amp;lt;em&amp;gt;stupidly&amp;lt;/em&amp;gt; useful and allow people to prototype programming languages in &amp;lt;em&amp;gt;hours&amp;lt;/em&amp;gt;. I really do not understand why there are not 10 of those already. Can someone please make this?&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I think by the time most people are capable of doing something like this, they already got nerd-sniped into parsing theory and lose sight of the forest for the trees.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="links"&amp;gt;Links&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;These links say some of the things I said here, but not as clearly distressed and much more measured and intelligent:&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://matklad.github.io/2018/06/06/modern-parser-generator.html"&amp;gt;Modern Parser Generator&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://tiarkrompf.github.io/notes/?/just-write-the-parser/aside1"&amp;gt;Just write the #!%/* parser&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://utcc.utoronto.ca/~cks/space/blog/programming/WhyRDParsersForMe"&amp;gt;Why I write recursive descent parsers (despite their issues)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;h2 id="foot-notes"&amp;gt;Foot Notes&amp;lt;/h2&amp;gt;
&amp;lt;h3 id="error-recovery"&amp;gt;Error Recovery&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;Most people do not need it. You need it for parsers in IDEs for language servers and stuff like that, but most of the time you just want to error out on the first error. Whenever I get an error in any programming language, I just skip to the first one and doing anything else is (almost) always a waste of time. Imho error recovery is overrated.&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>eBPF File System Monitoring</title>
        
        <link href="https://joelschumacher.de/posts/ebpf-file-system-monitoring"/>
        <id>https://joelschumacher.de/posts/ebpf-file-system-monitoring</id>
        <updated>2025-01-27T12:13:00+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;This blog post is about something I am currently working on at work, so it will be partly about file system monitoring, somewhat about the file system code in the Linux kernel and a whole lot about eBPF, which is very cool.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Say we want to monitor file system changes on a system that hosts thousands of containers for thousands of customers that can be accessed however they like. Most commonly files are modified through SSH/SFTP, but it could be anything they can come up with. It should also work fairly independent of the filesystem. And we want to know about such files changing rather quickly (sub-second would be great), so scanning once a day is not good enough. Of course we are on Linux, because this is where all the cool things happen and also where all the cool kids hang out. We don&amp;amp;rsquo;t just want to know about all operations happening on files, but operations that would have us &amp;lt;em&amp;gt;read&amp;lt;/em&amp;gt; something else from them, i.e. that make their contents change. I.e. a write by itself is not interesting, but a write followed by a flush or a close is interesting!&amp;lt;/p&amp;gt;
&amp;lt;h2 id="existing-monitoring-apis"&amp;gt;Existing Monitoring APIs&amp;lt;/h2&amp;gt;
&amp;lt;h3 id="inotify"&amp;gt;inotify&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;This API is most commonly used for filesystem monitoring on Linux I would say (apart from possibly &amp;lt;a href="https://linux.die.net/man/2/stat"&amp;gt;&amp;lt;code&amp;gt;stat&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt;-ing in a loop), because it doesn&amp;amp;rsquo;t require any capabilities or privileges, it&amp;amp;rsquo;s easy to use and can do most things people care about.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Unfortunately you have to watch every file and directory separately - you can&amp;amp;rsquo;t watch recursively! &amp;amp;ldquo;inotify&amp;amp;rdquo; stands for &amp;amp;ldquo;inode notify&amp;amp;rdquo;, because you monitor single inodes. Of course this scales very badly with a large (or very large - as in our case) number of files. On my personal computer with just my stuff on it I have seen Sublime Text exhaust the number of inotify file descriptors multiple times (the limit can be increased, I know).&amp;lt;/p&amp;gt;
&amp;lt;h3 id="fanotify"&amp;gt;fanotify&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;Instead of monitoring single inodes, you can monitor mount points, which is much better, but with many thousands of containers, which all have their own mount namespace, it might not scale well either. It also requires &amp;lt;code&amp;gt;CAP_SYS_ADMIN&amp;lt;/code&amp;gt; to use.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="ebpf"&amp;gt;eBPF&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;This is gaining popularity in recent years for all sorts of reasons and people have been doing many cool things with it (see &amp;lt;a href="https://github.com/bpftrace/bpftrace"&amp;gt;bpftrace&amp;lt;/a&amp;gt; and &amp;lt;a href="https://github.com/iovisor/bcc"&amp;gt;bcc&amp;lt;/a&amp;gt;). It allows you to attach small programs to hooks, which are existing functions in user space or in kernel space. These small programs (&amp;lt;a href="https://bughunters.google.com/blog/6303226026131456/a-deep-dive-into-cve-2023-2163-how-we-found-and-fixed-an-ebpf-linux-kernel-vulnerability"&amp;gt;ideally&amp;lt;/a&amp;gt;) do not risk the stability or security of your operating system, because they are compiled to a dedicated bytecode, which is verified by the Kernel when it is attached to a hook. The eBPF verifier makes sure that your program terminates in finite time, that stack size is bounded and that it does not access memory out of bounds. More on that in a later section.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The most important aspects that make eBPF attractive for high performance file system monitoring is that we can pre-filter events in the Kernel, to reduce the amount of events we have to transfer. We can also mark data as soon as the syscall is issued or returned, which can reduce latency. Also we only require &amp;lt;code&amp;gt;CAP_BPF&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CAP_PERFMON&amp;lt;/code&amp;gt; to attach a eBPF program, but might require more depending on the program and attach point. After it is attached, we don&amp;amp;rsquo;t need any special permissions in user space to process the events generated by the eBPF program. Of course there is no state about watched items and way fewer layers than for example fanotify (vfs -&amp;amp;gt; fsnotify -&amp;amp;gt; fanotify -&amp;amp;gt; userspace). You can also optimize how exactly events are dispatched. And if you want to add additional information (like the mount namespace, the pid of the process that modified the file, etc.) you can (often) trivially add this information.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;So there are definitely good reasons it might be cool, let&amp;amp;rsquo;s try it!&amp;lt;/p&amp;gt;
&amp;lt;h3 id="what-to-trace"&amp;gt;What to Trace&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;Maybe this is not a smart way to think about this, but I considered ways I can edit a file, which syscall sequence this corresponds to and then looked at functions that might be good candidates. I am sure I have forgotten many.&amp;lt;/p&amp;gt;
&amp;lt;h4 id="operations"&amp;gt;Operations&amp;lt;/h4&amp;gt;
&amp;lt;p&amp;gt;These are the ones I could come up:&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://linux.die.net/man/2/write"&amp;gt;&amp;lt;code&amp;gt;write&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt; a (non-zero) number of times and then &amp;lt;a href="https://linux.die.net/man/2/close"&amp;gt;&amp;lt;code&amp;gt;close&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt; (C API: &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://linux.die.net/man/2/write"&amp;gt;&amp;lt;code&amp;gt;write&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt; a (non-zero) number of times and then &amp;lt;a href="https://linux.die.net/man/2/fsync"&amp;gt;&amp;lt;code&amp;gt;fsync&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt; (C API: &amp;lt;code&amp;gt;fflush&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://linux.die.net/man/2/write"&amp;gt;&amp;lt;code&amp;gt;write&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt; a (non-zero) number of times and the kernel does an automatic write-back&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://linux.die.net/man/2/writev"&amp;gt;&amp;lt;code&amp;gt;writev&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://linux.die.net/man/2/mmap"&amp;gt;&amp;lt;code&amp;gt;mmap&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt;, modify the mapped memory and then call &amp;lt;a href="https://linux.die.net/man/2/msync"&amp;gt;&amp;lt;code&amp;gt;msync&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://linux.die.net/man/2/mmap"&amp;gt;&amp;lt;code&amp;gt;mmap&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt;, modify the mapped memory and then call &amp;lt;a href="https://linux.die.net/man/2/close"&amp;gt;&amp;lt;code&amp;gt;close&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://linux.die.net/man/2/mmap"&amp;gt;&amp;lt;code&amp;gt;mmap&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt; and the kernel does an automatic write-back&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://linux.die.net/man/2/sendfile"&amp;gt;&amp;lt;code&amp;gt;sendfile&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://linux.die.net/man/2/splice"&amp;gt;&amp;lt;code&amp;gt;splice&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://linux.die.net/man/2/truncate"&amp;gt;&amp;lt;code&amp;gt;truncate&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://linux.die.net/man/2/rename"&amp;gt;&amp;lt;code&amp;gt;rename&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;p&amp;gt;Now we need to find the functions in the Linux kernel that we need to trace to catch all these different ways a file can be modified. Ideally we want to pick functions that take parameters from which we can easily obtain the information we want to collect.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;In user space Linux programs tend to interact with files using file descriptors, which are just integers, but internally these will be mapped to &amp;lt;code&amp;gt;struct file&amp;lt;/code&amp;gt; objects. File system related system calls then call into VFS (Virtual File System), which is an abstraction layer over all file systems with functions like &amp;lt;code&amp;gt;vfs_write&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;vfs_close&amp;lt;/code&amp;gt; and many more. VFS functions then use &amp;lt;code&amp;gt;file-&amp;amp;gt;f_op&amp;lt;/code&amp;gt; of type &amp;lt;code&amp;gt;struct file_operations*&amp;lt;/code&amp;gt;, which is just a collection of function pointers like &amp;lt;code&amp;gt;read&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;flush&amp;lt;/code&amp;gt; pointing to the actual functions that implement the specific file system (of which there are many).&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;If for example we traced on the &amp;lt;code&amp;gt;close&amp;lt;/code&amp;gt; system call itelf, we would just get the file descriptor in our eBPF program and we would have to get all the useful information from that ourselves, which is often not even possible in a restricted eBPF program, because you cannot call arbitray kernel functions. So it makes sense to trace on &amp;lt;code&amp;gt;vfs_close&amp;lt;/code&amp;gt;, which takes a &amp;lt;code&amp;gt;struct file&amp;lt;/code&amp;gt; instead. Unfortunately this function particular is inlined! And if there is no jump to that function, we cannot hook into it. The next interesting function in the call chain is &amp;lt;code&amp;gt;filp_close&amp;lt;/code&amp;gt;, which calls into &amp;lt;code&amp;gt;f_op&amp;lt;/code&amp;gt; directly, so it&amp;amp;rsquo;s the last function to trace that is not already part of a specific file system.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;This also means that flushing on close is not handled by VFS, but by the file system itself and we can&amp;amp;rsquo;t get away by just tracing the flush operation, but we have to trace &amp;lt;code&amp;gt;filp_close&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The next way to modify a file we consider is &amp;lt;code&amp;gt;fsync&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;fsync&amp;lt;/code&amp;gt; calls into &amp;lt;code&amp;gt;vfs_sync&amp;lt;/code&amp;gt;, which calls into &amp;lt;code&amp;gt;vfs_sync_range&amp;lt;/code&amp;gt;, which then calls into &amp;lt;code&amp;gt;f_op&amp;lt;/code&amp;gt;, so &amp;lt;code&amp;gt;vfs_sync_range&amp;lt;/code&amp;gt; is what we want to trace additionally.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Similarly the automatically triggered write-back of dirty pages and &amp;lt;code&amp;gt;msync&amp;lt;/code&amp;gt; all end up in &amp;lt;code&amp;gt;vfs_sync_range&amp;lt;/code&amp;gt;, but I won&amp;amp;rsquo;t go into detail for all of these. You may dig through the Kernel source yourself to verify.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;You would think &amp;lt;code&amp;gt;writev&amp;lt;/code&amp;gt; just does &amp;lt;code&amp;gt;write&amp;lt;/code&amp;gt;, but that&amp;amp;rsquo;s not true. It calls into &amp;lt;code&amp;gt;vfs_writev&amp;lt;/code&amp;gt;!&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="https://linux.die.net/man/2/sendfile"&amp;gt;&amp;lt;code&amp;gt;sendfile&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt; calls &amp;lt;code&amp;gt;do_splice_direct&amp;lt;/code&amp;gt; if the output is a file and eventually ends up calling &amp;lt;code&amp;gt;do_splice_from&amp;lt;/code&amp;gt;, which calls &amp;lt;code&amp;gt;fs_op-&amp;amp;gt;splice_write&amp;lt;/code&amp;gt; directly without a VFS layer function anywhere inbetween. &amp;lt;a href="https://linux.die.net/man/2/splice"&amp;gt;&amp;lt;code&amp;gt;splice&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt; also ends up in &amp;lt;code&amp;gt;do_splice_from&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;truncate&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rename&amp;lt;/code&amp;gt; call into &amp;lt;code&amp;gt;vfs_truncate&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;vfs_rename&amp;lt;/code&amp;gt; respectively.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;This leaves us with the following functions to trace:&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;filp_close&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;vfs_sync_range&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;vfs_writev&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;do_splice_from&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;vfs_truncate&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;vfs_rename&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;p&amp;gt;I had hoped there were fewer.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="tricky-bits"&amp;gt;Tricky Bits&amp;lt;/h2&amp;gt;
&amp;lt;h3 id="paths"&amp;gt;Paths&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;As a human I cannot deal well with the sort of data that is passed to e.g. &amp;lt;code&amp;gt;filp_close&amp;lt;/code&amp;gt;. That&amp;amp;rsquo;s just a &amp;lt;code&amp;gt;struct file*&amp;lt;/code&amp;gt;. I want more - I want paths. I started with &amp;lt;code&amp;gt;filp_close&amp;lt;/code&amp;gt; and struggled immensely to get the absolute path from the &amp;lt;code&amp;gt;struct file*&amp;lt;/code&amp;gt; only to learn later that this was one of the easy functions.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Essentially a &amp;lt;code&amp;gt;struct path&amp;lt;/code&amp;gt; in the Linux kernel is a &amp;lt;code&amp;gt;struct dentry *dentry&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;struct vfsmount *mnt&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;dentry&amp;lt;/code&amp;gt; contains the name of the filesystem object and a pointer to its parent &amp;lt;code&amp;gt;dentry&amp;lt;/code&amp;gt;. This is not enough, because the end of this linked list is not the filesystem root, but the root of the mount point. This is why you need the &amp;lt;code&amp;gt;struct vfsmount *mnt&amp;lt;/code&amp;gt; as well to get to the full path.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;So essentially you have to read the kernel source and figure out ways to get to the data you want from the data you have. It&amp;amp;rsquo;s not impossible, which is why it&amp;amp;rsquo;s not listed under problems, but it is tricky, hence the section this piece of text is placed in.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="the-verifier"&amp;gt;The Verifier&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;A good chunk of the time, especially in the beginning, I spent on trying to please the eBPF verifier. After you learn how it works and some tricks, it stops being a constant annoyance.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;As you might know it is hard (read: &amp;lt;a href="https://en.wikipedia.org/wiki/Halting_problem"&amp;gt;in general impossible&amp;lt;/a&amp;gt;) to say whether a program terminates. So the eBPF verifier imposes some restrictions on the kinds of programs you write. As the verifier has to enumerate all possible paths of your program and analyze them individually, you may only produce a finite number of paths. In practice this number doesn&amp;amp;rsquo;t just have to be finite, but bounded (1 million instructions in total at the time of this writing). Essentially this means that you mostly have to use bounded loops and if you can&amp;amp;rsquo;t tell that your program is finishing in finite time, the verifier will not either.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;So instead of this:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;c
while ((node = node-&amp;amp;gt;next)) {
    // ...
}&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;you should probably write this:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;c
for (int i = 0; i &amp;amp;lt; MAX_NUM_NODES; ++i)
{
    /// ...
    node = node-&amp;amp;gt;next;
}&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I haven&amp;amp;rsquo;t had much trouble with this limiation and on top of that the verifier has become much smarter about unbounded loops in recent kernel versions.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The really tricky bit are memory accesses though. In regular C code you would confidently write this:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;c
if (offset + size &amp;amp;lt;= BUF_SIZE) {
    bpf_probe_read_kernel(buf + offset, size, some_kernel_ptr);
}&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;That&amp;amp;rsquo;s safe, right? Well, go ask the verifier - he will not agree.
The verifier keeps track of every register and it&amp;amp;rsquo;s possible value range, but it will not track the range of a value in relation to another. So if for example the only thing the verifier knows about a value &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; is that in all possible universes it might be in the range &amp;lt;code&amp;gt;[0, 4096]&amp;lt;/code&amp;gt;, another value &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; is also in &amp;lt;code&amp;gt;[0, 4096]&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;BUF_SIZE&amp;lt;/code&amp;gt;, the size of the buffer &amp;lt;code&amp;gt;buf&amp;lt;/code&amp;gt;, is &amp;lt;code&amp;gt;4096&amp;lt;/code&amp;gt;, then there is no way to encode the constraint from &amp;lt;code&amp;gt;if (offset + size &amp;amp;lt;= BUF_SIZE)&amp;lt;/code&amp;gt;. Consequently it will complain that &amp;lt;code&amp;gt;bpf_probe_read_kernel&amp;lt;/code&amp;gt; might cause an out of bounds memory access, because &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; are both in &amp;lt;code&amp;gt;[0, 4096]&amp;lt;/code&amp;gt;. After all it is possible that both &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; are &amp;lt;code&amp;gt;4096&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;In practice this means that you need to double your buffers a lot, so that e.g. if &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; are in &amp;lt;code&amp;gt;[0, 4096]&amp;lt;/code&amp;gt;, the size of &amp;lt;code&amp;gt;buf&amp;lt;/code&amp;gt; should be &amp;lt;code&amp;gt;8192&amp;lt;/code&amp;gt;. Then you can never have an out of bounds memory access.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;You also need to sprinkle your code with macros that explicitly limit the range of values, like this:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;```c&amp;lt;/p&amp;gt;
&amp;lt;h1 id="define-path_buf_size-4096"&amp;gt;define PATH_BUF_SIZE 4096&amp;lt;/h1&amp;gt;
&amp;lt;h1 id="define-limit_path_buf_sizex-x-path_buf_size-1"&amp;gt;define LIMIT_PATH_BUF_SIZE(x) ((x) &amp;amp;amp;= (PATH_BUF_SIZE - 1))&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;// &amp;amp;hellip;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;LIMIT_PATH_BUF_SIZE(path_start);
```&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;When I started working on this I thought I could get away with just programming carefully, but you need to look at the eBPF assembly and see what&amp;amp;rsquo;s actually going on to understand some of the errors.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;For example look at this funny little thing:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;c
name_len++;
if (name_len &amp;amp;gt; path_start) {
  break;
}&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;{ guess_lang = False }
; name_len++;
97: (07) r2 += 1                       ; R2_w=scalar(umin=1,umax=4294967296,
                                       ;   var_off=(0x0; 0x1ffffffff))
98: (bf) r1 = r2                       ; R1_w=scalar(id=6,umin=1,umax=4294967296,
                                       ;   var_off=(0x0; 0x1ffffffff))
                                       ; R2_w=scalar(id=6,umin=1,umax=4294967296,
                                       ;   var_off=(0x0; 0x1ffffffff))
99: (67) r1 &amp;amp;lt;&amp;amp;lt;= 32                     ; R1_w=scalar(smax=9223372032559808512,
                                       ;   umax=18446744069414584320,
                                       ;   var_off=(0x0; 0xffffffff00000000),
                                       ;   s32_min=0,s32_max=0,u32_max=0)
100: (77) r1 &amp;amp;gt;&amp;amp;gt;= 32                    ; R1=scalar(umax=4294967295,
                                       ;   var_off=(0x0; 0xffffffff))
; if (name_len &amp;amp;gt; path_start) {
101: (25) if r1 &amp;amp;gt; 0x1000 goto pc+2051  ; R1=scalar(umax=4096,var_off=(0x0; 0x1fff))&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Here &amp;lt;code&amp;gt;name_len&amp;lt;/code&amp;gt; is stored in &amp;lt;code&amp;gt;r2&amp;lt;/code&amp;gt;. In instruction 97 it is incremented. &amp;lt;code&amp;gt;path_start&amp;lt;/code&amp;gt; is just &amp;lt;code&amp;gt;4096&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;umin&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;umax&amp;lt;/code&amp;gt; values in the comments indicate the known ranges of the registers and are just another way to display &amp;lt;code&amp;gt;var_off&amp;lt;/code&amp;gt;. The problem with this snippet is that the verifier will not update the range of &amp;lt;code&amp;gt;name_len&amp;lt;/code&amp;gt;, despite &amp;lt;code&amp;gt;if (name_len &amp;amp;gt; path_start) break&amp;lt;/code&amp;gt;. In general it will exclude paths that you &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; from and update value ranges accordingly. This is because here &amp;lt;code&amp;gt;name_len&amp;lt;/code&amp;gt; is a 32-bit unsigned int and &amp;lt;code&amp;gt;r2&amp;lt;/code&amp;gt; is a 64-bit register, so the increment might push &amp;lt;code&amp;gt;r2&amp;lt;/code&amp;gt; out of 32-bit range. To perform the check in instruction 101, the compiler has to bring &amp;lt;code&amp;gt;r1&amp;lt;/code&amp;gt; back into 32-bit range by shifting it up (instruction 99) and down again (instruction 100). Unfortunately the compiler decided to use another register (&amp;lt;code&amp;gt;r1&amp;lt;/code&amp;gt;) for this and as a result the verifier doesn&amp;amp;rsquo;t know that it should update &amp;lt;code&amp;gt;r2&amp;lt;/code&amp;gt;. It&amp;amp;rsquo;s possible to program around these things, but it can be very annoying and it will frequently bug you.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="actual-problems"&amp;gt;Actual Problems&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;While those things above need getting used to and are managable, there are also problems that aren&amp;amp;rsquo;t solved well with elbow grease.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="paths_1"&amp;gt;Paths&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;I mentioned that &amp;lt;code&amp;gt;filp_close&amp;lt;/code&amp;gt; was one of the easy functions, implying there might more difficult ones. The one I had in mind here is &amp;lt;code&amp;gt;vfs_rename&amp;lt;/code&amp;gt;. It takes a &amp;lt;code&amp;gt;struct renamedata*&amp;lt;/code&amp;gt;, which looks like this:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;c
struct renamedata {
    struct mnt_idmap *old_mnt_idmap;
    struct inode *old_dir;
    struct dentry *old_dentry;
    struct mnt_idmap *new_mnt_idmap;
    struct inode *new_dir;
    struct dentry *new_dentry;
    struct inode **delegated_inode;
    unsigned int flags;
} __randomize_layout;&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Just &amp;lt;code&amp;gt;dentry&amp;lt;/code&amp;gt;s and &amp;lt;code&amp;gt;inode&amp;lt;/code&amp;gt;s. But to build a full path I need a &amp;lt;code&amp;gt;vfsmount&amp;lt;/code&amp;gt;! I haven&amp;amp;rsquo;t found a way to get it. I considered other functions to trace, but I haven&amp;amp;rsquo;t found a good solution. You cannot call into arbitrary functions in the kernel from eBPF, which is why it&amp;amp;rsquo;s not as easy as just doing what you would do in the kernel.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;My current workaround is to just traverse the &amp;lt;code&amp;gt;dentry&amp;lt;/code&amp;gt; list and build a path up until the mount root. Then include this path in the event passed to userspace and the mount namespace id. As root, this should be enough to uniquely identify the file that was modified. I am sure I am still missing something for when the same filesystem is bind-mounted multiple times.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="unstable-abi"&amp;gt;Unstable ABI&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;Another reason I have to go with the mount root path is that to traverse up to the parent mount, I need to get the &amp;lt;code&amp;gt;struct mount&amp;lt;/code&amp;gt; that contains the &amp;lt;code&amp;gt;struct vfsmount&amp;lt;/code&amp;gt;. I use &amp;lt;code&amp;gt;container_of&amp;lt;/code&amp;gt; for this, but &amp;lt;code&amp;gt;struct mount&amp;lt;/code&amp;gt; is not in a public header, so I have to define a (sufficient) subset myself. This is what I did:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;c
struct mount {
    struct hlist_head mnt_hash; // list_head -&amp;amp;gt; hlist_head Al Viro 2014 (same size)
    struct mount *mnt_parent;
    struct dentry *mnt_mountpoint; // Al Viro 2011 inserted
    struct vfsmount mnt;
    // lots more fields, that are partially dependent on compilation flags
};&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I added some comments to note when these fields were last changed. Linux tries to have a stable API (&amp;lt;a href="https://lkml.org/lkml/2012/12/23/75"&amp;gt;&amp;amp;ldquo;WE DO NOT BREAK USERSPACE&amp;amp;rdquo;&amp;lt;/a&amp;gt;), but it does not have a stable ABI! This means such structs may change. This means your eBPF programs might break on every new kernel release and even if they don&amp;amp;rsquo;t change, your distro might have a good reason to change it. As unstable as the kernel ABI is, your eBPF programs are likely too.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Inserting new fields or reordering them somehow is annoying enough, but it&amp;amp;rsquo;s possible refactors take away fields you depend on all together and then you don&amp;amp;rsquo;t just have to recompile your program, but solve your problem again from the beginning. This might incur a significant maintenance burden, especially considering this is usually not a particularly simple task.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="__randomize_layout"&amp;gt;&amp;lt;code&amp;gt;__randomize_layout&amp;lt;/code&amp;gt;&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;I purposely left it in the definition of &amp;lt;code&amp;gt;renamedata&amp;lt;/code&amp;gt; above to get you guessing! Many structures in the Linux kernel are marked with &amp;lt;code&amp;gt;__randomize_layout&amp;lt;/code&amp;gt; so that its members are shuffled during compile time. This makes certain exploits more difficult as the offsets to critical structures are unknown.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Unfortunately we depend on some of those offsets! The full version of my small &amp;lt;code&amp;gt;struct mount&amp;lt;/code&amp;gt; above is actually marked &amp;lt;code&amp;gt;__randomize_layout&amp;lt;/code&amp;gt; as well. Meaning, if struct randomization is enabled in your kernel, there is no way to implement this full path traversal properly in an eBPF program.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Fortunately (?) many distros (such as Debian and Ubuntu) disable struct randomization. You can check this by running &amp;lt;code&amp;gt;grep CONFIG_RANDSTRUCT /boot/config-$(uname -r)&amp;lt;/code&amp;gt;, which should return &amp;lt;code&amp;gt;CONFIG_RANDSTRUCT_NONE=y&amp;lt;/code&amp;gt; if it is disabled.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;But if you use a distro that has it enabled or have some requirements to enable it, then certain things will be very difficult (or impossible) to do in an eBPF program.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I have later realized that smarter people are aware of this issue. You can use &amp;lt;a href="https://www.kernel.org/doc/html/latest/bpf/btf.html"&amp;gt;BTF&amp;lt;/a&amp;gt; and &amp;lt;a href="https://docs.ebpf.io/concepts/core/"&amp;gt;CO-RE&amp;lt;/a&amp;gt; (Compile Once - Run Everywhere) to generate headers with the actual struct layouts. I will only need the file system monitoring on distros that have struct randomization disabled, so I haven&amp;amp;rsquo;t looked into it yet.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="conclusion"&amp;gt;Conclusion&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;eBPF can be used for high performance file system monitoring, but it is possibly unstable and not very portable. If you control the target system very well, that might not be a huge problem. Also it is definitely some trouble to collect all the possible syscalls that might end up modifying a file on your disk and I am not sure I got them all. Even if I did, new ways could be added tomorrow or in a year. It seems efficient and flexible, but fragile, which is a difficult tradeoff. It&amp;amp;rsquo;s the kind of thing where the tradeoff might be worth it today, but with an ongoing maintenance burden, that tradeoff might slowly become less favorable.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I am sure I should look into CO-RE and BTF because they alleviate some of my concerns, but I don&amp;amp;rsquo;t think it will clear them all up.&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>Game Engine Requirements</title>
        
        <link href="https://joelschumacher.de/posts/game-engine-requirements"/>
        <id>https://joelschumacher.de/posts/game-engine-requirements</id>
        <updated>2025-01-15T20:27:00+0000</updated>
        <content type="html">&amp;lt;h2 id="introduction"&amp;gt;Introduction&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;A few days ago I found &amp;lt;a href="https://racenis.github.io/tram-sdk/why.html"&amp;gt;Tramway SDK&amp;lt;/a&amp;gt; on HackerNews and I thought its design decisions and motiviations really resonated with me.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I have been keeping similar notes on why I want to make my own engine scattered across my hard drive for years and thought maybe I should write it down and extend it over time as a living document.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Of course I know this is not how every engine should be and I certainly don&amp;amp;rsquo;t think there is a huge market for an engine as I am describing it here, but it is what &amp;lt;strong&amp;gt;I&amp;lt;/strong&amp;gt; want.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="table-of-contents"&amp;gt;Table of Contents&amp;lt;/h2&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="#no-editor-code-first"&amp;gt;No Editor / Code First&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="#no-intentionally-opaque-shit"&amp;gt;No Intentionally Opaque Shit&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="#vcs-aware"&amp;gt;VCS aware&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="#usability-over-architecture"&amp;gt;Usability over Architecture&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="#target-audience-experienced-programmers"&amp;gt;Target Audience: Experienced Programmers&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="#fast-iteration-time"&amp;gt;Fast Iteration Time&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="#small-scope"&amp;gt;Small Scope&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="#cross-platform"&amp;gt;Cross-Platform&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="#single-executable"&amp;gt;Single Executable&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;h2 id="details"&amp;gt;Details&amp;lt;/h2&amp;gt;
&amp;lt;h3 id="no-editor-code-first"&amp;gt;No Editor / Code First&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;I hate editors so fucking much. Of course you need to place your objects in the level with an editor, but I don&amp;amp;rsquo;t want to do literally everything in the damn editor.
Whatever engine you are today, your UI is way too fucking full of stuff, it&amp;amp;rsquo;s dog shit slow and most of the time just plain weird.
Digging through layers of options dialogs and settings makes me want to cry, turn off the computer and never turn it on again.
Editor UIs just evolve &amp;lt;strong&amp;gt;horribly&amp;lt;/strong&amp;gt;. Every new thing increases the complexity of everything else.
And almost always they are so fucking buggy it makes you lose respect and faith in the software altogether.
Instead everything should be handled in code, human-readable text(-ish) files and via CLI tools that can be automated and used in scripts at every step of the way.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="no-intentionally-opaque-shit"&amp;gt;No Intentionally Opaque Shit&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;I don&amp;amp;rsquo;t want your silly files that are not documented properly anywhere. Even if your stuff is open source, I do not care. I want &amp;lt;em&amp;gt;official&amp;lt;/em&amp;gt; specifications or open file formats (even better)!
If I need to do some modification to a file, I don&amp;amp;rsquo;t want to modify the engine, but write my own tool. This is how an engine is actually easily extensible!
If the engine needs proprietary file formats (which it very likely does, that is normal), they should have proper specifications or ideally be so simple that a brief glance tells you all you need to know.
Also I don&amp;amp;rsquo;t want any files I&amp;amp;rsquo;m not supposed to understand, because they should &amp;lt;em&amp;gt;just work&amp;lt;/em&amp;gt; (or something). They don&amp;amp;rsquo;t - constantly. Every file should be for the developers to consume and produce, no other garbage please.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="vcs-aware"&amp;gt;VCS aware&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;When I say VCS aware of course I mean git. If your engine works great with version control and that means &amp;amp;ldquo;just Perforce&amp;amp;rdquo; or god forbid some proprietary thing, that doesn&amp;amp;rsquo;t count. I DO NOT CARE.
Every file the engine tools write to or reads from the disk should be VCS friendly (i.e. doesn&amp;amp;rsquo;t diff randomly and auto-merges well). This sort of implies that all interesting files are either assets (like textures, sounds, meshes) or human-readable text files.
I am human, let me read my files!
This also ties into the previous section - I don&amp;amp;rsquo;t want to think about whether a file should or should not be added to VCS. It should be obvious.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="usability-over-architecture"&amp;gt;Usability over Architecture&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;I have wasted quite a few years building engines with grand concepts and beautiful architectures that ended up not being very useful or putting road blocks in my way while doing simple things, so that I could make complex things easier.
There are plenty of architecture astronauts that build abstract temples made of archetypal ECSs with relationships, queries and schedulers and I think most of you are going too far.
If you built the most amazing architecture and no one has made a real game with it in 5 years (there are multiple popular examples of this), then you should consider if you went too far as well.
Abstractions make sense and are necessary, but they should solve a problem and too often they solve problems, that (approximately) no one really has yet.
So the engine should have just as much abstraction as necessary. Imho if there is any grand, clever architectural idea in your engine you might brag about on your website, that is a &amp;lt;em&amp;gt;big negative&amp;lt;/em&amp;gt;, not a positive!&amp;lt;/p&amp;gt;
&amp;lt;h3 id="target-audience-experienced-programmers"&amp;gt;Target Audience: Experienced Programmers&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;So many engines are built for people that just get started and don&amp;amp;rsquo;t know what they are doing yet.
It&amp;amp;rsquo;s great those engines exist, but if you have some general experience with game development, you tend to fight a lot against the &amp;amp;ldquo;noob-layer&amp;amp;rdquo; put on top of everything.
My engine should be made for experienced &amp;lt;em&amp;gt;programmers&amp;lt;/em&amp;gt; (not artists or designers), that have made (multiple) games before.
You should know how to use a computer and you know how it works and you are not afraid of code or the terminal.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="fast-iteration-time"&amp;gt;Fast Iteration Time&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;It should never take more than one second (non-negotiable) to try out a change you have made to game code (engine code is not included).
I have worked on some C++ games, where the iteration times went up to 30s and it killed curiosity to try out things, the joy in development and ultimately the fun.
I have also worked on software that takes 15min to (incremental!) build and you just end up adopting weird habits to avoid rebuilding.
As soon as you develop a hint of laziness about experimenting with your game, there is no way you will make it as good as you can.
In practice this means you either do something crazy (shared libs with game code in C) or you use scripting (Lua is my strong preference).&amp;lt;/p&amp;gt;
&amp;lt;h3 id="small-scope"&amp;gt;Small Scope&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;It&amp;amp;rsquo;s purposely made for game jam games and small/medium indie games. Making AAA stuff possible should never be a design goal or constraint.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The engine is not does-it-all.
If you make a bigger game or want to do something special, it&amp;amp;rsquo;s guaranteed you need your own build of the engine (with significant modifications).
It should include a basic version of &amp;lt;em&amp;gt;everything&amp;lt;/em&amp;gt; and a fancy version of &amp;lt;em&amp;gt;absolutely nothing&amp;lt;/em&amp;gt;. Only the simplest usable thing is built-in.
Everything gets sucky over time, because it grows and bloats and tries to solve every problem for everyone.
So you have to commit to not add every feature that might be useful to someone and maybe not even fix every bug. You should try to keep it small &amp;lt;em&amp;gt;aggressively&amp;lt;/em&amp;gt;, but of course add everything that almost everyone needs.
Half the reason I hate most engines is because they are &amp;amp;ldquo;do everything&amp;amp;rdquo; tools.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Even if you use something big like Unity or whatever, if you make a serious game, you eventually have to make your own specialized tools anyways and write your own libs and everything else.
They include the feature-complete option already, but they are so &amp;amp;ldquo;feature complete&amp;amp;rdquo; (read: bloated), that it gets simpler to just remake the damn thing with 10% of the features, because you gain stability and speed.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Making a single tool that works for ten different people is often less work than making a tool that works for a single person once.
And if you have those ten tools, they are faster and easier to use and more tailored the users needs.
Users of the engine should be expected to replace certain parts according to their needs.
Reinventing the wheel exists, but people try to avoid it too much and they should &amp;amp;ldquo;reinvent&amp;amp;rdquo; it more often.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="cross-platform"&amp;gt;Cross-Platform&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;The engine can be built on Windows and Linux and both are equally important. And you can build your game for Windows, Linux, Mac and Web &amp;lt;em&amp;gt;out of the box&amp;lt;/em&amp;gt;.
&amp;lt;code&amp;gt;engine build --release mygame/&amp;lt;/code&amp;gt; should give you distributables for all platforms without much fuss.
Increasingly many game jams require all submissions to be playable in the browser, therefore a web export is very important.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="single-executable"&amp;gt;Single Executable&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;Yes, everything you want to do is in that executable. This makes for an easy download and easy experiments.
You can run your debug builds with it, you can create your release builds with it, you can convert your assets. Everything the engine needs to do, is in that single executable.
This is not in contrast to what I said in &amp;lt;a href="#small-scope"&amp;gt;Small Scope&amp;lt;/a&amp;gt;, because I am talking about a means of software distribution only. This is about the stuff that is part of the engine anyways.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="final-note"&amp;gt;Final Note&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;I didn&amp;amp;rsquo;t expect this to bring out such anger, but I think it stems from bad experiences I have made with existing engines and it is likely this anger that drives me towards making my own.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I should also mention that &amp;lt;a href="https://love2d.org/"&amp;gt;löve&amp;lt;/a&amp;gt; comes very close to almost all of these requirements. I&amp;amp;rsquo;ve used and enjoyed it for a very long time, but it&amp;amp;rsquo;s mostly geared towards 2D games and most of the games I want to make today are 3D games.
Also there are a few smaller things I wish it did differently (only user directory is writable, there should be official build tools, etc.).&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>Yet Another C++ Coroutine Tutorial</title>
        
        <link href="https://joelschumacher.de/posts/yet-another-cpp-coroutine-tutorial"/>
        <id>https://joelschumacher.de/posts/yet-another-cpp-coroutine-tutorial</id>
        <updated>2023-04-24T18:34:24+0000</updated>
        <content type="html">&amp;lt;h2 id="introduction"&amp;gt;Introduction&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;I know, everyone has written one.
My grandma recently published hers, after telling me how bad she finds the one her hairdresser wrote.
I suspect many people have similar experiences of pouring a dozen of these resources into their heads and still wondering how the HELL these fucking things work and when they finally figure it out, they want to write it down too - &amp;amp;ldquo;properly&amp;amp;rdquo; this time.
This is exactly what I will do in this blog post as well.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Let me note that some of the sentences in this post are frankly just ridiculous.
You have to read them carefully, word by word, and think hard about what they say.
I think this topic is truly complicated and there is no other way but understanding that complexity.
Hopefully this post can help you with that and lead to somewhere where you can operate coroutines in code that does something useful and interesting.
If not and you find certain questions not adequately answered or entirely unadressed, feel free to write me an email and help me make this tutorial better.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I first tried to write this tutorial with some small classes that fake doing async IO, but it became hard to extend the examples to something meaningful, so instead I will use my own async IO library &amp;lt;a href="https://github.com/pfirsich/aiopp"&amp;gt;aiopp&amp;lt;/a&amp;gt;. Reading along should be enough and this blog post is intended to be self-contained, but if you want to run some of the code, look around in the &amp;lt;a href="https://github.com/pfirsich/aiopp"&amp;gt;aiopp&amp;lt;/a&amp;gt; repository (especially &amp;lt;code&amp;gt;examples/&amp;lt;/code&amp;gt;). In fact most of the snippets in this blog post are parts or simplified versions of code in that repository.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;For this tutorial I will assume that you have some idea of what coroutines are, but to summarize briefly, they are functions that can suspend themselves, meaning they stop themselves &amp;lt;em&amp;gt;without returning&amp;lt;/em&amp;gt;, even in the middle of their body and then can later can be resumed, continuing execution at the point they suspended from earlier.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;So when in the past you would write something like this (lots of complications and error handling omited):&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;cpp
io.read(fd, buffer.data(), buffer.size(),
    [](std::error_code ec, size_t readBytes) {
        buffer.resize(readBytes);
        handleReadData(buffer);
    });&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;With coroutines you would just do this:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;cpp
std::vector&amp;amp;lt;uint8_t&amp;amp;gt; buffer(1024, 0);
const auto [ec, readBytes] = co_await io.read(fd, buffer.data(), buffer.size());
buffer.resize(readBytes);
handleReadData(buffer);&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;It &amp;lt;em&amp;gt;looks&amp;lt;/em&amp;gt; like synchronous code, but &amp;lt;code&amp;gt;co_await&amp;lt;/code&amp;gt; will suspend the execution of the function (coroutine) that contains this code, your program does something else (like waiting for the read to complete) and when the read is finished, the coroutine will be resumed and the read can be handled.
You don&amp;amp;rsquo;t really have to worry about whether the operation might outlive a buffer or about sharing ownership of the object that initiated the operation (a coroutine) with the IO operation.
Of course you have to worry about it once, when you build the framework and that&amp;amp;rsquo;s bad enough, but after that it will not invite you repeatedly to mess it up, like callback based async code does.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;In a conventional function the variables live on the stack and when the function returns, the whole stack frame is thrown away.
A stack frame of a function will never outlive the stack frame of the function that called it.
With a coroutine of course this is not possible, so the coroutine state is typically allocated on the heap.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="my-first-coroutine"&amp;gt;My First Coroutine&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;Let&amp;amp;rsquo;s start with the minimal coroutine example I can come up with, explain it and build it up:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;```cpp&amp;lt;/p&amp;gt;
&amp;lt;h1 id="include"&amp;gt;include &amp;lt;coroutine&amp;gt;&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;class BasicCoroutine {
public:
    struct Promise {
        BasicCoroutine get_return_object() { return BasicCoroutine {}; }&amp;lt;/p&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;    void unhandled_exception() noexcept { }

    void return_void() noexcept { }

    std::suspend_never initial_suspend() noexcept { return {}; }
    std::suspend_never final_suspend() noexcept { return {}; }
};
using promise_type = Promise;
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;p&amp;gt;};&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;BasicCoroutine coro()
{
    co_return;
}&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;int main()
{
    coro();
}

&amp;lt;div class="codehighlight" style="background: #282828"&amp;gt;&amp;lt;pre style="line-height: 125%;"&amp;gt;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;code&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;em&amp;amp;gt;&amp;lt;/span&amp;gt;(this example is self-contained)&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/em&amp;amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;Not very small, I know.
And it doesn&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rsquo;&amp;lt;/span&amp;gt;t do anything either - Already love them!
I promise I&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rsquo;&amp;lt;/span&amp;gt;ll build it up to something useful, but let&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rsquo;&amp;lt;/span&amp;gt;s first analyze this snippet.
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;coro&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; is a coroutine simply because it contains the keyword &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;co_return&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt;.
If a function contains &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;co_await&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt;, &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;co_return&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; or &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;co_yield&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt;, it&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rsquo;&amp;lt;/span&amp;gt;s a coroutine.
The return type, even though it doesn&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rsquo;&amp;lt;/span&amp;gt;t do much, has to be this complicated, because coroutines are rewritten by the compiler in a certain way.
This is what a coroutine is rewritten as:&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;cpp
ReturnType someCoroutine(Parameters parameter)
{
    auto* frame = new coroutineFrame(std::forward&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;lt;&amp;lt;/span&amp;gt;Parameters&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;gt;&amp;lt;/span&amp;gt;(parameters));
    auto returnObject = frame-&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;gt;&amp;lt;/span&amp;gt;promise.get_return_object();
    co_await frame-&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;gt;&amp;lt;/span&amp;gt;promise.initial_suspend();
    try
    {
        &amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;lt;&amp;lt;/span&amp;gt;body-statements&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;gt;&amp;lt;/span&amp;gt;
    }
    catch (...)
    {
        frame-&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;gt;&amp;lt;/span&amp;gt;promise.unhandled_exception();
    }
    co_await frame-&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;gt;&amp;lt;/span&amp;gt;promise.final_suspend();
    delete frame;
    return returnObject;
}&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;So as we said earlier, the coroutine frame, called the &amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;ldquo;&amp;lt;/span&amp;gt;coroutine state&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rdquo;&amp;lt;/span&amp;gt; is allocated on the heap, the function parameters of the coroutine and later all local variables and temporaries are saved inside it.
Another object is also allocated inside it, which is called the &amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;ldquo;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;em&amp;amp;gt;&amp;lt;/span&amp;gt;promise&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/em&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rdquo;&amp;lt;/span&amp;gt;.
There are different ways the compiler can select a promise type for a coroutine, but what we will use for now is that it will look for &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;ReturnType::promise_type&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; (see also the minimal example).
It might be worth mentioning, that there are also &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;coroutine_traits&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; which you can use to associate a promise type with any coroutine return type, e.g. standard library types.
Most of the logic of the coroutine (apart from it&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rsquo;&amp;lt;/span&amp;gt;s body) is handled through the promise.
When we later suspend the coroutine, the coroutine state will also contain information about the point we suspended from, so we can resume to that point later.&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;Then the return object of the coroutine is created through the promise.
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;get_return_object&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; has to return something that is convertible to the return type of the coroutine.&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;The promise member functions &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;initial_suspend&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; and &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;final_suspend&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; return &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;em&amp;amp;gt;&amp;lt;/span&amp;gt;awaitables&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/em&amp;amp;gt;&amp;lt;/span&amp;gt; and provide an opportunity to control the behavior of the coroutine at the start and the end.
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;em&amp;amp;gt;&amp;lt;/span&amp;gt;Awaitables&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/em&amp;amp;gt;&amp;lt;/span&amp;gt; are just things you can &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;co_await&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt;.
Depending on the return type of your coroutine, the coroutine itself might be awaitable, but other things can be awaitable as well.
I would say that most things you &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;co_await&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; are not coroutines (e.g. &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;io.recv()&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; above is not).
I will explain awaitables in detail shortly but for now know that &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;co_await std::suspend_never&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; is pretty much a noop and terminates immediately, without suspending the coroutine - it seems the name has been chosen well!
A common choice for &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;initial_suspend&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; is also &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;std::suspend_always&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt;, which will result in your coroutine suspending immediately after creating the return object.
This would correspond to a &amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;ldquo;&amp;lt;/span&amp;gt;cold-start&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rdquo;&amp;lt;/span&amp;gt; or &amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;ldquo;&amp;lt;/span&amp;gt;lazy&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rdquo;&amp;lt;/span&amp;gt; coroutine, which you will have to resume at least once first before it starts executing its body.
The coroutine from our minimal example is analogously called a &amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;ldquo;&amp;lt;/span&amp;gt;hot-start&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rdquo;&amp;lt;/span&amp;gt; or &amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;ldquo;&amp;lt;/span&amp;gt;eager&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rdquo;&amp;lt;/span&amp;gt; coroutine.&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;Additionally upon reaching &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;co_return &amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;lt;&amp;lt;/span&amp;gt;expr&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;gt;&amp;lt;/span&amp;gt;;&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;promise.return_void()&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; or &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;promise.return_value(&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;lt;&amp;lt;/span&amp;gt;expr&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;gt;&amp;lt;/span&amp;gt;)&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; is called, depending on whether &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;lt;&amp;lt;/span&amp;gt;expr&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; is void or not and which function is defined for the &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;em&amp;amp;gt;&amp;lt;/span&amp;gt;promise&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/em&amp;amp;gt;&amp;lt;/span&amp;gt; type.
Note that &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;return_value&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; also returns &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;void&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; and it is used to store the value that was &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;co_return&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt;ed inside the promise.
If the coroutine returns void, &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;return_void&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; is also called at the end of the body, even if the coroutine does not contain &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;co_return;&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; explicitly.&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;Our next goal is to &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;co_await&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/span&amp;gt; something!&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;h2&amp;lt;/span&amp;gt; &amp;lt;span style="color: #fabd2f"&amp;gt;id=&amp;lt;/span&amp;gt;&amp;lt;span style="color: #b8bb26"&amp;gt;&amp;amp;quot;awaitables&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;gt;&amp;amp;lt;em&amp;amp;gt;&amp;lt;/span&amp;gt;Awaitables&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/em&amp;amp;gt;&amp;amp;lt;/h2&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;Let&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rsquo;&amp;lt;/span&amp;gt;s start with half a UDP echo server first, that we will then coroutinize (sic):
```cpp&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;h1&amp;lt;/span&amp;gt; &amp;lt;span style="color: #fabd2f"&amp;gt;id=&amp;lt;/span&amp;gt;&amp;lt;span style="color: #b8bb26"&amp;gt;&amp;amp;quot;include-aioppioqueuehpp&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;gt;&amp;lt;/span&amp;gt;include &amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;ldquo;&amp;lt;/span&amp;gt;aiopp/ioqueue.hpp&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rdquo;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/h1&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;h1&amp;lt;/span&amp;gt; &amp;lt;span style="color: #fabd2f"&amp;gt;id=&amp;lt;/span&amp;gt;&amp;lt;span style="color: #b8bb26"&amp;gt;&amp;amp;quot;include-aioppsockethpp&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;gt;&amp;lt;/span&amp;gt;include &amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;ldquo;&amp;lt;/span&amp;gt;aiopp/socket.hpp&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rdquo;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/h1&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;h1&amp;lt;/span&amp;gt; &amp;lt;span style="color: #fabd2f"&amp;gt;id=&amp;lt;/span&amp;gt;&amp;lt;span style="color: #b8bb26"&amp;gt;&amp;amp;quot;include-spdloggerhpp&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;gt;&amp;lt;/span&amp;gt;include &amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;ldquo;&amp;lt;/span&amp;gt;spdlogger.hpp&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rdquo;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/h1&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;using namespace aiopp;&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;class Server {
public:
    Server(IoQueue&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;amp;&amp;lt;/span&amp;gt; io, Fd&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;amp;&amp;amp;amp;amp;&amp;lt;/span&amp;gt; socket)
        : io_(io)
        , socket_(std::move(socket))
    {
    }&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;void start() { receive(); }
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;private:
    void receive()
    {
        receiveBuffer_.resize(1024, &amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;lsquo;&amp;lt;/span&amp;gt;\0&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rsquo;&amp;lt;/span&amp;gt;);
        io_.recvfrom(socket_, receiveBuffer_.data(), receiveBuffer_.size(), 0,
            &amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;amp;&amp;lt;/span&amp;gt;clientAddr_,
            &amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;a&amp;lt;/span&amp;gt; &amp;lt;span style="color: #fabd2f"&amp;gt;href=&amp;lt;/span&amp;gt;&amp;lt;span style="color: #b8bb26"&amp;gt;&amp;amp;quot;std::error_code ec, int receivedBytes&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;gt;&amp;lt;/span&amp;gt;this&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/a&amp;amp;gt;&amp;lt;/span&amp;gt; {
                if (ec) {
                    spdlog::error(&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;ldquo;&amp;lt;/span&amp;gt;Error in recvfrom: {}&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rdquo;&amp;lt;/span&amp;gt;, ec.message());
                    receive();
                    return;
                }&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;            receiveBuffer_.resize(receivedBytes);
            spdlog::info(&amp;amp;quot;received: &amp;amp;#39;{}&amp;amp;#39;&amp;amp;quot;, receiveBuffer_);
            receive();
        });
}

IoQueue&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;amp;&amp;lt;/span&amp;gt; io_;
Fd socket_;
std::string receiveBuffer_;
::sockaddr_in clientAddr_;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;};&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;int main()
{
    setLogger(std::make_unique&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;SpdLogger&amp;amp;gt;&amp;lt;/span&amp;gt;());&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;auto socket = createSocket(SocketType::Udp,
    IpAddress::parse(&amp;amp;quot;0.0.0.0&amp;amp;quot;).value(), 4242);
if (socket == -1) {
    return 1;
}

IoQueue io;
Server server(io, std::move(socket));
server.start();
io.run();
return 0;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #8ec07c"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;}
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;


&amp;lt;em&amp;gt;The full echo server is here: &amp;lt;a href="https://github.com/pfirsich/aiopp/blob/main/examples/echo-udp.cpp"&amp;gt;echo-udp.cpp&amp;lt;/a&amp;gt;&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I hope you can guess well enough what all the aiopp stuff does.
Note that I simplified the ownership of some of the objects.
Everything is in &amp;lt;code&amp;gt;Server&amp;lt;/code&amp;gt; and as long as that lives longer than &amp;lt;code&amp;gt;io.run()&amp;lt;/code&amp;gt; runs, we&amp;amp;rsquo;re fine.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;To build a coroutine version of this application, we need to create an &amp;lt;em&amp;gt;awaitable&amp;lt;/em&amp;gt; for &amp;lt;code&amp;gt;recvfrom&amp;lt;/code&amp;gt; operations.
An &amp;lt;em&amp;gt;awaitable&amp;lt;/em&amp;gt; is an object for which &amp;lt;code&amp;gt;operator co_await&amp;lt;/code&amp;gt; is defined. There is also another way via &amp;lt;code&amp;gt;promise_type::await_transform&amp;lt;/code&amp;gt;, but we won&amp;amp;rsquo;t discuss that in this blog post.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Before I explain more, I will show you an &amp;lt;em&amp;gt;awaitable&amp;lt;/em&amp;gt; for our &amp;lt;code&amp;gt;recvfrom&amp;lt;/code&amp;gt; operation:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;```cpp
struct IoResult {
    std::error_code ec;
    int result;
};&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;class RecvFromAwaitable {
public:
    RecvFromAwaitable(IoQueue&amp;amp;amp; io, int socket, void&amp;lt;em&amp;gt; buf, size_t len,
        ::sockaddr_in&amp;lt;/em&amp;gt; srcAddr)
        : io_(io)
        , socket_(socket)
        , buf_(buf)
        , len_(len)
        , srcAddr_(srcAddr)
    {
    }&amp;lt;/p&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;auto operator co_await()
{
    struct Awaiter {
        RecvFromAwaitable&amp;amp;amp; awaitable;
        IoResult result = {};

        bool await_ready() const noexcept { return false; }

        void await_suspend(std::coroutine_handle&amp;amp;lt;&amp;amp;gt; handle) noexcept
        {
            awaitable.io_.recvfrom(awaitable.socket_, awaitable.buf_,
                awaitable.len_, 0, awaitable.srcAddr_,
                [this, handle](std::error_code ec, int receivedBytes) {
                    result = IoResult { ec, receivedBytes };
                    handle.resume();
                });
        }

        IoResult await_resume() const noexcept { return result; }
    };
    return Awaiter { *this };
}
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;p&amp;gt;private:
    IoQueue&amp;amp;amp; io_;
    int socket_;
    void&amp;lt;em&amp;gt; buf_;
    size_t len_;
    ::sockaddr_in&amp;lt;/em&amp;gt; srcAddr_;
};
```&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;operator co_await&amp;lt;/code&amp;gt; must return an &amp;lt;em&amp;gt;awaiter&amp;lt;/em&amp;gt; object, which should provide three methods: &amp;lt;code&amp;gt;await_ready&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;await_suspend&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;await_resume&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;When an &amp;lt;em&amp;gt;awaitable&amp;lt;/em&amp;gt; is &amp;lt;code&amp;gt;co_await&amp;lt;/code&amp;gt;ed, the &amp;lt;code&amp;gt;operator co_await&amp;lt;/code&amp;gt; is executed and the &amp;lt;em&amp;gt;awaiter&amp;lt;/em&amp;gt; is obtained from it. Then &amp;lt;code&amp;gt;awaiter.await_ready()&amp;lt;/code&amp;gt; is called.
If it returns &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;, the coroutine does not suspend and &amp;lt;code&amp;gt;await_resume&amp;lt;/code&amp;gt; is called immediately, producing the return value of the expression.
This is how &amp;lt;code&amp;gt;std::suspend_never&amp;lt;/code&amp;gt; works - It simply returns &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;await_ready()&amp;lt;/code&amp;gt;!
If &amp;lt;code&amp;gt;await_ready&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;, the coroutine is suspended, meaning all state necessary to resume it later is stored in the coroutine state and &amp;lt;code&amp;gt;await_suspend&amp;lt;/code&amp;gt; is called, being passed a &amp;lt;a href="https://en.cppreference.com/w/cpp/coroutine/coroutine_handle"&amp;gt;&amp;lt;code&amp;gt;std::coroutine_handle&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt; to the coroutine being suspended.
Among other things and most importantly this handle can be used to resume the coroutine later.
When a suspended coroutine is resumed, &amp;lt;code&amp;gt;await_resume&amp;lt;/code&amp;gt; is called, returning the result to be produced by the &amp;lt;code&amp;gt;co_await&amp;lt;/code&amp;gt; expression.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I keep a reference to the &amp;lt;em&amp;gt;awaitable&amp;lt;/em&amp;gt; in the &amp;lt;em&amp;gt;awaiter&amp;lt;/em&amp;gt; which should be fine, because both objects live until the end of the &amp;lt;code&amp;gt;co_await&amp;lt;/code&amp;gt; expression and the &amp;lt;em&amp;gt;awaiter&amp;lt;/em&amp;gt; will be destroyed before the &amp;lt;em&amp;gt;awaitable&amp;lt;/em&amp;gt;.
By the way you could also create an awaiter directly and &amp;lt;code&amp;gt;co_await&amp;lt;/code&amp;gt; that (without the &amp;lt;em&amp;gt;awaitable&amp;lt;/em&amp;gt; in between), but that is a less conventional approach and I would not have an opportunity to demonstrate &amp;lt;code&amp;gt;operator co_await&amp;lt;/code&amp;gt; to you. And of course it would not work with this &amp;lt;em&amp;gt;awaiter&amp;lt;/em&amp;gt;, because it needs a reference to an &amp;lt;em&amp;gt;awaitable&amp;lt;/em&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;We can use our new awaitable like this:

&amp;lt;div class="codehighlight" style="background: #282828"&amp;gt;&amp;lt;pre style="line-height: 125%;"&amp;gt;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;code&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;BasicCoroutine serve(IoQueue&amp;amp;amp;amp; io, &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; Fd&amp;amp;amp;amp; socket)&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;{&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;while&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fe8019"&amp;gt;true&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        std::string receiveBuffer(&amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;1024&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;, &amp;amp;amp;lsquo;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #282828; background-color: #fb4934"&amp;gt;\&amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;0&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rsquo;);&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        ::sockaddr_in clientAddr;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; [recvEc, receivedBytes] = &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; RecvFromAwaitable(&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            io, socket, receiveBuffer.data(), receiveBuffer.size(), &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;0&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;, &amp;amp;amp;amp;clientAddr);&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;if&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (recvEc) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            spdlog::error(&amp;amp;amp;ldquo;Error in recvfrom: {}&amp;amp;amp;rdquo;, recvEc.message());&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;continue&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        receiveBuffer.resize(receivedBytes);&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        spdlog::info(&amp;amp;amp;ldquo;received: &amp;amp;amp;lsquo;{}&amp;amp;amp;rsquo;&amp;amp;amp;ldquo;, receiveBuffer);&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;}&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;int&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; main()&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;{&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; socket = createSocket(SocketType::Udp,&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        IpAddress::parse(&amp;amp;amp;ldquo;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;0.0.0.0&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rdquo;).value(), &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;4242&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;);&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;if&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (socket == &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;-1&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;1&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;IoQueue io;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;serve(io, socket);&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;io.run();&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;0&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;}&amp;lt;/span&amp;gt;
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;


&amp;lt;em&amp;gt;The full echo server is here: &amp;lt;a href="https://github.com/pfirsich/aiopp/blob/main/examples/echo-udp-coro.cpp"&amp;gt;echo-udp-coro.cpp&amp;lt;/a&amp;gt;&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Isn&amp;amp;rsquo;t that much prettier?
There is much less noise and stupid lambdas and code that doesn&amp;amp;rsquo;t even tell you what the program actually does.
It&amp;amp;rsquo;s much easier to understand too, ignoring the (high) complexity hidden in the &amp;lt;code&amp;gt;RecvFromAwaitable&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;BasicCoroutine&amp;lt;/code&amp;gt; (more of that to come btw.).&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Let&amp;amp;rsquo;s recap:&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;main()&amp;lt;/code&amp;gt; is called and calls &amp;lt;code&amp;gt;serve&amp;lt;/code&amp;gt;&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;The coroutine state is allocated, including the &amp;lt;em&amp;gt;promise&amp;lt;/em&amp;gt; object&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;The return object of the coroutine is created via &amp;lt;code&amp;gt;promise.get_return_object()&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;co_await promise.initial_suspend()&amp;lt;/code&amp;gt; is executed, which in our case is &amp;lt;code&amp;gt;co_await std::suspend_never{}&amp;lt;/code&amp;gt;, i.e. it terminates immediately - the coroutine body starts executing&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;A &amp;lt;code&amp;gt;RecvFromAwaitable&amp;lt;/code&amp;gt; is constructed packaging the parameters of our async IO operation&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;The &amp;lt;em&amp;gt;awaiter&amp;lt;/em&amp;gt; is obtained from the &amp;lt;code&amp;gt;RecvFromAwaitable&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;awaiter.await_ready()&amp;lt;/code&amp;gt; returns false, so the coroutine is suspended&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;await_suspend()&amp;lt;/code&amp;gt; is called, which initiates the async IO operation (recvfrom), storing the handle to the suspended coroutine in the lambda callback.&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Since &amp;lt;code&amp;gt;serve&amp;lt;/code&amp;gt; suspended, it returned control to the caller and we are back in &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;io.run()&amp;lt;/code&amp;gt; is called and we wait to receive a message&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;io.recvfrom&amp;lt;/code&amp;gt; completes and the callback is called&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;We store the result inside the &amp;lt;em&amp;gt;awaiter&amp;lt;/em&amp;gt; and call &amp;lt;code&amp;gt;handle.resume()&amp;lt;/code&amp;gt; to resume the coroutine (&amp;lt;code&amp;gt;serve&amp;lt;/code&amp;gt;)&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;await_resume&amp;lt;/code&amp;gt; is called inside &amp;lt;code&amp;gt;serve&amp;lt;/code&amp;gt; to produce the result of the &amp;lt;code&amp;gt;co_await&amp;lt;/code&amp;gt; expression.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;The return value is processed and we print the received message&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;We &amp;lt;code&amp;gt;co_await RecvFromAwaitable&amp;lt;/code&amp;gt; again (see above)&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;h2 id="tcp-echo-server"&amp;gt;TCP Echo Server&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;Please pretend that I built various other classes like &amp;lt;code&amp;gt;RecvFromAwaitable&amp;lt;/code&amp;gt; for other methods of &amp;lt;code&amp;gt;IoQueue&amp;lt;/code&amp;gt;.
In reality I wrote some ugly template class that packages arguments into a tuple and then applies them to the lambda, inclusion of which in here would distract too much from the topic of this blog post.
Eventually we have a few functions that return &amp;lt;em&amp;gt;awaitables&amp;lt;/em&amp;gt; for other &amp;lt;code&amp;gt;IoQueue&amp;lt;/code&amp;gt; methods that could be copy-pasted from the &amp;lt;code&amp;gt;RecvFromAwaitable&amp;lt;/code&amp;gt; above (but aren&amp;amp;rsquo;t). In the following I will pretend we have such functions for &amp;lt;code&amp;gt;accept&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;recv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;send&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Take a look at this simple TCP echo server:

&amp;lt;div class="codehighlight" style="background: #282828"&amp;gt;&amp;lt;pre style="line-height: 125%;"&amp;gt;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;code&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;BasicCoroutine echo(IoQueue&amp;amp;amp;amp; io, Fd socket)&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;{&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;while&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fe8019"&amp;gt;true&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        std::string recvBuffer(&amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;1024&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;, &amp;amp;amp;lsquo;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #282828; background-color: #fb4934"&amp;gt;\&amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;0&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rsquo;);&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; [rec, receivedBytes]&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            = &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; recv(io, socket, recvBuffer.data(), recvBuffer.size());&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;if&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (rec) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            spdlog::error(&amp;amp;amp;ldquo;Error in receive: {}&amp;amp;amp;rdquo;, rec.message());&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;break&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        }&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;if&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (receivedBytes == &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;0&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;) { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #928374; font-style: italic"&amp;gt;// Connection closed&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;break&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    recvBuffer.resize(receivedBytes);&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; [sec, sentBytes]&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        = &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; send(io, socket, recvBuffer.data(), recvBuffer.size());&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;if&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (sec) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        spdlog::error(&amp;lt;/span&amp;gt;&amp;lt;span style="color: #b8bb26"&amp;gt;&amp;amp;quot;Error in send: {}&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;, sec.message());&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;break&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;if&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (sentBytes == &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;0&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;) { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #928374; font-style: italic"&amp;gt;// Connection closed&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;break&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;}&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;}&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;BasicCoroutine serve(IoQueue&amp;amp;amp;amp; io, Fd&amp;amp;amp;amp;&amp;amp;amp;amp; listenSocket)&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;{&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;while&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fe8019"&amp;gt;true&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; [ec, fd] = &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; accept(io, listenSocket, &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;nullptr&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;, &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;nullptr&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;);&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;if&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (ec) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            spdlog::error(&amp;amp;amp;ldquo;Error in accept: {}&amp;amp;amp;rdquo;, ec.message());&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;continue&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        echo(io, Fd { fd });&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;}&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;int&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; main()&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;{&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; socket = createTcpListenSocket(IpAddress::parse(&amp;amp;amp;ldquo;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;0.0.0.0&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rdquo;).value(), &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;4242&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;);&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;if&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (socket == &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;-1&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;1&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;IoQueue io;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;serve(io, std::move(socket));&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;io.run();&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;0&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;}&amp;lt;/span&amp;gt;
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;


&amp;lt;em&amp;gt;The final echo server is here: &amp;lt;a href="https://github.com/pfirsich/aiopp/blob/main/examples/echo-tcp-coro.cpp"&amp;gt;echo-tcp-coro.cpp&amp;lt;/a&amp;gt;&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;With what we did so far, this should already work!
You can interact with it by running &amp;lt;code&amp;gt;nc 127.0.0.1 4242&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Also we did something cool here, which might not be obvious right away. We &amp;lt;code&amp;gt;co_await accept&amp;lt;/code&amp;gt; in a loop and call &amp;lt;code&amp;gt;echo&amp;lt;/code&amp;gt; afterwards, which will handle a single connection.
This makes it possible to handle multiple clients at once, without extra effort.
When &amp;lt;code&amp;gt;accept&amp;lt;/code&amp;gt; completes, i.e. we got a new connection and &amp;lt;code&amp;gt;serve&amp;lt;/code&amp;gt; is resumed, we call echo, which will immediately &amp;lt;code&amp;gt;co_await recv&amp;lt;/code&amp;gt; and return control back to us, so we can accept again, so that both &amp;lt;code&amp;gt;accept&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;recv&amp;lt;/code&amp;gt; are issued at the same time.
Pretty sweet!&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Here it becomes important that we chose to use &amp;lt;code&amp;gt;std::suspend_never&amp;lt;/code&amp;gt; for &amp;lt;code&amp;gt;final_suspend&amp;lt;/code&amp;gt;!
You will often (later) see task types (like &amp;lt;code&amp;gt;BasicCoroutine&amp;lt;/code&amp;gt;) that keep a handle to a coroutine and clean it up in the destructor, like &amp;lt;code&amp;gt;if (handle_) handle_.destroy()&amp;lt;/code&amp;gt;.
In this case you would have to change &amp;lt;code&amp;gt;final_suspend&amp;lt;/code&amp;gt; to return &amp;lt;code&amp;gt;std::suspend_always&amp;lt;/code&amp;gt; (or something else that suspends).&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;With &amp;lt;code&amp;gt;std::suspend_never&amp;lt;/code&amp;gt;, as we learned earlier (see above to remind yourself), the coroutine will not suspend after executing the coroutine body and the coroutine state will be destroyed immediately.
This will invalidate all coroutine handles.
So if we called &amp;lt;code&amp;gt;handle_.destroy()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;~BasicCoroutine&amp;lt;/code&amp;gt;, the coroutine would be long dead and our coroutine handle would be dangling, which would result in a use-after-free bug (or double-free if you will).
Of course it is not just illegal (straight to jail) to destroy a coroutine through a dangling handle, but to do anything with it, including checking if the coroutine is done!&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Analogously if you use &amp;lt;code&amp;gt;std::suspend_always&amp;lt;/code&amp;gt; for &amp;lt;code&amp;gt;final_suspend&amp;lt;/code&amp;gt;, the coroutine state will not be destroyed automatically and you &amp;lt;strong&amp;gt;have to&amp;lt;/strong&amp;gt; destroy the coroutine through its handle if you don&amp;amp;rsquo;t want to leak it.
If we went for this approach, our &amp;lt;code&amp;gt;BasicCoroutine&amp;lt;/code&amp;gt; destructor would have destroyed the coroutine and since &amp;lt;code&amp;gt;echo(io, Fd { fd })&amp;lt;/code&amp;gt; returns a temporary &amp;lt;code&amp;gt;BasicCoroutine&amp;lt;/code&amp;gt;, the &amp;lt;code&amp;gt;BasicCoroutine&amp;lt;/code&amp;gt; would destroy the coroutine as soon as we suspend &amp;lt;code&amp;gt;echo&amp;lt;/code&amp;gt; from the first &amp;lt;code&amp;gt;co_await recv&amp;lt;/code&amp;gt; and return control to &amp;lt;code&amp;gt;serve&amp;lt;/code&amp;gt;.
In summary we want our coroutine to outlive the &amp;lt;code&amp;gt;BasicCoroutine&amp;lt;/code&amp;gt; objects, because we don&amp;amp;rsquo;t use them and they get destroyed early.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;There is still a tiny problem with this.
Since TCP is a stream protocol, send might not send all the data we have given it, i.e. &amp;lt;code&amp;gt;sentBytes&amp;lt;/code&amp;gt; might be less than &amp;lt;code&amp;gt;recvBuffer.size()&amp;lt;/code&amp;gt; and we should actually send in a loop until the whole buffer has been sent or an error occured (or the connection was closed).
Ideally we would just introduce a new function &amp;lt;code&amp;gt;sendAll&amp;lt;/code&amp;gt; which will do what I just explained, like so:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;```cpp
BasicCoroutine sendAll(IoQueue&amp;amp;amp; io, const Fd&amp;amp;amp; socket, const std::string&amp;amp;amp; buffer)
{
    size_t offset = 0;
    while (offset &amp;amp;lt; buffer.size()) {
        const auto [ec, sentBytes]
            = co_await send(io, socket, buffer.data() + offset,
                buffer.size() - offset);
        if (ec) {
            spdlog::error(&amp;amp;ldquo;Error in send: {}&amp;amp;rdquo;, ec.message());
            co_return;
        }&amp;lt;/p&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;    if (sentBytes == 0) {
        co_return;
    }

    offset += sentBytes;
}
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;p&amp;gt;}
```&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Unfortunately we cannot simply call this function from &amp;lt;code&amp;gt;echo&amp;lt;/code&amp;gt;.
If we did, the &amp;lt;code&amp;gt;send&amp;lt;/code&amp;gt;s from &amp;lt;code&amp;gt;sendAll&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;recv&amp;lt;/code&amp;gt;s from &amp;lt;code&amp;gt;echo&amp;lt;/code&amp;gt; would get interleaved just like the &amp;lt;code&amp;gt;accept&amp;lt;/code&amp;gt;s from &amp;lt;code&amp;gt;serve&amp;lt;/code&amp;gt; and the &amp;lt;code&amp;gt;recv&amp;lt;/code&amp;gt;s from &amp;lt;code&amp;gt;echo&amp;lt;/code&amp;gt;.
And since &amp;lt;code&amp;gt;sendAll&amp;lt;/code&amp;gt; is holding a reference to the receive buffer, this interleaving might cause the receive buffer to get changed by the &amp;lt;code&amp;gt;echo&amp;lt;/code&amp;gt; function under our feet!
Even if we do a simple fix of copying the entire buffer and passing it into &amp;lt;code&amp;gt;sendAll&amp;lt;/code&amp;gt; by value (dirty and lazy), another &amp;lt;code&amp;gt;recv&amp;lt;/code&amp;gt; could in theory complete before the &amp;lt;code&amp;gt;sendAll&amp;lt;/code&amp;gt; and initiate &amp;lt;em&amp;gt;another&amp;lt;/em&amp;gt; &amp;lt;code&amp;gt;sendAll&amp;lt;/code&amp;gt;, potentially destroying the stream property of the TCP connection by interleaving data that should not be interleaved.
To be correct, we should pass control to &amp;lt;code&amp;gt;sendAll&amp;lt;/code&amp;gt; until it finishes sending data and only then regain control in &amp;lt;code&amp;gt;echo&amp;lt;/code&amp;gt; - or in other words: we want to &amp;lt;code&amp;gt;co_await sendAll()&amp;lt;/code&amp;gt;!&amp;lt;/p&amp;gt;
&amp;lt;h2 id="awaitable-coroutines"&amp;gt;Awaitable Coroutines&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;Let&amp;amp;rsquo;s just try to &amp;lt;code&amp;gt;co_await&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;BasicCoroutine&amp;lt;/code&amp;gt;:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;```cpp
BasicCoroutine echo(IoQueue&amp;amp;amp; io, Fd socket)
{
    while (true) {
        std::string recvBuffer(1024, &amp;amp;lsquo;\0&amp;amp;rsquo;);
        spdlog::info(&amp;amp;ldquo;recv&amp;amp;rdquo;);
        const auto [rec, receivedBytes]
            = co_await recv(io, socket, recvBuffer.data(), recvBuffer.size());
        if (rec) {
            spdlog::error(&amp;amp;ldquo;Error in receive: {}&amp;amp;rdquo;, rec.message());
            break;
        }&amp;lt;/p&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;    if (receivedBytes == 0) { // Connection closed
        break;
    }

    recvBuffer.resize(receivedBytes);
    co_await sendAll(io, socket, recvBuffer);
}
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;p&amp;gt;}
```&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Unfortunately we get the following error: &amp;lt;code&amp;gt;error: no member named 'await_ready' in 'BasicCoroutine'&amp;lt;/code&amp;gt;. This is because, like I said earlier, a coroutine doesn&amp;amp;rsquo;t have to be an &amp;lt;em&amp;gt;awaitable&amp;lt;/em&amp;gt; and ours isn&amp;amp;rsquo;t!
Fixing this means, that we have to provide an &amp;lt;code&amp;gt;operator co_await&amp;lt;/code&amp;gt; for our coroutine object.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Instead of extending &amp;lt;code&amp;gt;BasicCoroutine&amp;lt;/code&amp;gt;, we introduce a new &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; to be returned by &amp;lt;code&amp;gt;sendAll&amp;lt;/code&amp;gt; (more on why later).
The name of this class is borrowed from many other libraries and aligns with a proposal for a type to be added to the C++ standard.
Even programming languages like C# and Python use this name to represent an asynchronous operation that can be awaited, so we will use it too.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Let&amp;amp;rsquo;s start with a copy of &amp;lt;code&amp;gt;BasicCoroutine&amp;lt;/code&amp;gt;, but add a &amp;lt;code&amp;gt;operator co_await&amp;lt;/code&amp;gt;, so we can &amp;lt;code&amp;gt;co_await&amp;lt;/code&amp;gt; it:

&amp;lt;div class="codehighlight" style="background: #282828"&amp;gt;&amp;lt;pre style="line-height: 125%;"&amp;gt;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;code&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;class&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;Task&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #fb4934"&amp;gt;public&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;:&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;struct&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;Promise&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        Task &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;get_return_object&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; Task { }; }&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; unhandled_exception() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; return_void() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    std::suspend_never initial_suspend() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {}; }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    std::suspend_never final_suspend() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {}; }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;};&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #fb4934"&amp;gt;using&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; promise_type = Promise;&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #fb4934"&amp;gt;struct&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;Awaiter&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;bool&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;await_ready&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fe8019"&amp;gt;false&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;; }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_suspend(std::coroutine_handle&amp;amp;amp;lt;&amp;amp;amp;gt;) &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_resume() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;};&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;operator&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;{&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; Awaiter { };&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;}&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;};&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #282828; background-color: #fb4934"&amp;gt;```&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;What &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;do&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; we want our &amp;amp;lt;code&amp;amp;gt;Task&amp;amp;lt;/code&amp;amp;gt; to &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;do&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; really?&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;We want to suspend the calling coroutine (&amp;amp;lt;code&amp;amp;gt;echo&amp;amp;lt;/code&amp;amp;gt; in &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;this&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;case&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;), when we start &amp;amp;lt;code&amp;amp;gt;sendAll&amp;amp;lt;/code&amp;amp;gt; and only resume the calling coroutine, when &amp;amp;lt;code&amp;amp;gt;sendAll&amp;amp;lt;/code&amp;amp;gt; has finished.&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;The best way to hook into &amp;amp;amp;ldquo;when a coroutine has finished&amp;amp;amp;rdquo; is the &amp;amp;lt;em&amp;amp;gt;awaiter&amp;amp;lt;/em&amp;amp;gt; returned by &amp;amp;lt;code&amp;amp;gt;final_suspend&amp;amp;lt;/code&amp;amp;gt;, because as we learned earlier that awaiter will be suspended, when the coroutine body has completed.&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;That means we probably want to introduce a custom awaiter, which we will call &amp;amp;lt;code&amp;amp;gt;FinalAwaiter&amp;amp;lt;/code&amp;amp;gt;:&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #282828; background-color: #fb4934"&amp;gt;```&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;cpp&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #fb4934"&amp;gt;class&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;Task&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #fb4934"&amp;gt;public&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;:&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;struct&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;FinalAwaiter&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;bool&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;await_ready&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fe8019"&amp;gt;false&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;; }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_suspend(std::coroutine_handle&amp;amp;amp;lt;&amp;amp;amp;gt; handle) &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_resume() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    };&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;struct&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;Promise&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    Task &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;get_return_object&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; Task { }; }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;unhandled_exception&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;return_void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    std::suspend_never &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;initial_suspend&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {}; }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    FinalAwaiter &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;final_suspend&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {}; }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;};&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #fb4934"&amp;gt;using&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; promise_type = Promise;&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #fb4934"&amp;gt;struct&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;Awaiter&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;bool&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;await_ready&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fe8019"&amp;gt;false&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;; }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_suspend(std::coroutine_handle&amp;amp;amp;lt;&amp;amp;amp;gt;) &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_resume() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;};&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;operator&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;{&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; Awaiter { };&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;}&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;};&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #282828; background-color: #fb4934"&amp;gt;```&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;Now we have all the pieces and we just need to draw the rest of the fucking owl.&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;If we want to resume the calling coroutine later, we need to save a handle to it and we need to save it somewhere we can get to from &amp;amp;lt;code&amp;amp;gt;FinalAwaiter&amp;amp;lt;/code&amp;amp;gt;, which will be the &amp;amp;lt;em&amp;amp;gt;promise&amp;amp;lt;/em&amp;amp;gt;.&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;To get to the &amp;amp;lt;em&amp;amp;gt;promise&amp;amp;lt;/em&amp;amp;gt; from the &amp;amp;lt;code&amp;amp;gt;Awaiter&amp;amp;lt;/code&amp;amp;gt;, we need a handle to the coroutine that belongs to the &amp;amp;lt;code&amp;amp;gt;Task&amp;amp;lt;/code&amp;amp;gt;. Let&amp;amp;amp;rsquo;s start by passing that from &amp;amp;lt;code&amp;amp;gt;Promise::get_return_object&amp;amp;lt;/code&amp;amp;gt; to &amp;amp;lt;code&amp;amp;gt;Task()&amp;amp;lt;/code&amp;amp;gt; and keeping a copy in &amp;amp;lt;code&amp;amp;gt;Awaiter&amp;amp;lt;/code&amp;amp;gt; as well:&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #282828; background-color: #fb4934"&amp;gt;```&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;cpp&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #fb4934"&amp;gt;class&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;Task&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #fb4934"&amp;gt;public&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;:&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;struct&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;FinalAwaiter&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;bool&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;await_ready&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fe8019"&amp;gt;false&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;; }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_suspend(std::coroutine_handle&amp;amp;amp;lt;&amp;amp;amp;gt; handle) &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_resume() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    };&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;struct&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;Promise&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    Task &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;get_return_object&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;()&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; Task { std::coroutine_handle&amp;amp;amp;lt;Promise&amp;amp;amp;gt;::from_promise(*&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;this&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;) };&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;unhandled_exception&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;return_void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    std::suspend_never &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;initial_suspend&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {}; }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    FinalAwaiter &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;final_suspend&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {}; }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;};&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #fb4934"&amp;gt;using&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; promise_type = Promise;&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;Task() = &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;default&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #fb4934"&amp;gt;struct&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;Awaiter&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    std::coroutine_handle&amp;amp;amp;lt;Promise&amp;amp;amp;gt; handle;&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;bool&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;await_ready&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fe8019"&amp;gt;false&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;; }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_suspend(std::coroutine_handle&amp;amp;amp;lt;&amp;amp;amp;gt;) &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_resume() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;};&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;operator&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;{&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; Awaiter { handle_ };&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;}&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;private&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;:&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;explicit&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; Task(std::coroutine_handle&amp;amp;lt;Promise&amp;amp;gt; handle)&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        : handle_(handle)&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;std::coroutine_handle&amp;amp;amp;lt;Promise&amp;amp;amp;gt; handle_;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;};&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #282828; background-color: #fb4934"&amp;gt;```&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;Note that we specified the promise type explicitly &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;for&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; the newly introduced coroutine handles.&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;This is necessary to make the &amp;amp;lt;code&amp;amp;gt;.promise()&amp;amp;lt;/code&amp;amp;gt; method available.&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;Remember that a handle to the calling coroutine (the one that &amp;amp;lt;code&amp;amp;gt;co_awaits&amp;amp;lt;/code&amp;amp;gt; the &amp;amp;lt;code&amp;amp;gt;Task&amp;amp;lt;/code&amp;amp;gt;) is passed to &amp;amp;lt;code&amp;amp;gt;Awaiter::await_suspend&amp;amp;lt;/code&amp;amp;gt;.&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;Let&amp;amp;amp;rsquo;s add a member variable to &amp;amp;lt;code&amp;amp;gt;Promise&amp;amp;lt;/code&amp;amp;gt; and save a handle to the calling corouting in there.&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;We will call &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;this&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; member variable &amp;amp;lt;code&amp;amp;gt;continuation&amp;amp;lt;/code&amp;amp;gt;:&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #282828; background-color: #fb4934"&amp;gt;```&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;cpp&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;struct&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;Promise&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        std::coroutine_handle&amp;amp;amp;lt;&amp;amp;amp;gt; continuation;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;    Task get_return_object()&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; Task { std::coroutine_handle&amp;amp;amp;lt;Promise&amp;amp;amp;gt;::from_promise(*&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;this&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;) };&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; unhandled_exception() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; return_void() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    std::suspend_never initial_suspend() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {}; }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    FinalAwaiter final_suspend() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {}; }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;};&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #fb4934"&amp;gt;struct&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;Awaiter&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    std::coroutine_handle&amp;amp;amp;lt;Promise&amp;amp;amp;gt; handle;&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;bool&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;await_ready&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fe8019"&amp;gt;false&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;; }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_suspend(std::coroutine_handle&amp;amp;amp;lt;&amp;amp;amp;gt; calling) &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        handle.promise().continuation = calling;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_resume() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;};&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;};&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #282828; background-color: #fb4934"&amp;gt;```&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;Now all that&amp;amp;amp;rsquo;s left to make it work, is to get the &amp;amp;lt;code&amp;amp;gt;continuation&amp;amp;lt;/code&amp;amp;gt; handle in &amp;amp;lt;code&amp;amp;gt;FinalAwaiter::await_suspend&amp;amp;lt;/code&amp;amp;gt;, which is called when the called coroutine (&amp;amp;lt;code&amp;amp;gt;sendAll&amp;amp;lt;/code&amp;amp;gt;) completes, and &amp;amp;lt;code&amp;amp;gt;.resume()&amp;amp;lt;/code&amp;amp;gt; it:&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #282828; background-color: #fb4934"&amp;gt;```&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;cpp&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;struct&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;FinalAwaiter&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;bool&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;await_ready&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fe8019"&amp;gt;false&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;; }&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;template&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;amp;amp;lt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;typename&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;P&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_suspend(std::coroutine_handle&amp;amp;amp;lt;P&amp;amp;amp;gt; handle) &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        handle.promise().continuation.resume();&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_resume() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;};&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #282828; background-color: #fb4934"&amp;gt;```&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;We are not quite done, but &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;this&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; should work already.&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;Let&amp;amp;amp;rsquo;s iron out the kinks before we proceed.&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;First of all, since we now have a &amp;amp;lt;code&amp;amp;gt;FinalAwaiter&amp;amp;lt;/code&amp;amp;gt; which suspends, the coroutine state is not destroyed automatically anymore.&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;To prevent a memory leak, we need to add a destructor to &amp;amp;lt;code&amp;amp;gt;Task&amp;amp;lt;/code&amp;amp;gt;:&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;cpp&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            ~Task()&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;                &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;if&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (handle_) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;                    handle_.destroy();&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;                }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            }&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;This might also be a good time to mention that a coroutine is &amp;amp;amp;ldquo;done&amp;amp;amp;rdquo;, when it &amp;amp;amp;ldquo;is suspended at its &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;final&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; suspended point&amp;amp;amp;rdquo;, so when the &amp;amp;lt;em&amp;amp;gt;awaiter&amp;amp;lt;/em&amp;amp;gt; returned by &amp;amp;lt;code&amp;amp;gt;final_suspend&amp;amp;lt;/code&amp;amp;gt; has been &amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;ed.&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;The difference, again, between &amp;amp;lt;code&amp;amp;gt;await_ready&amp;amp;lt;/code&amp;amp;gt; returning &amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fe8019"&amp;gt;true&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt; or &amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fe8019"&amp;gt;false&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt; is whether the coroutine state is destroyed automatically, which is why we need to destroy it manually &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;this&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; time.&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;Also I find it a bit awkward, that when we start &amp;amp;lt;code&amp;amp;gt;sendAll&amp;amp;lt;/code&amp;amp;gt;, it starts doing its thing and suspends at &amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; send&amp;amp;lt;/code&amp;amp;gt;, control is passed back to us (&amp;amp;lt;code&amp;amp;gt;echo&amp;amp;lt;/code&amp;amp;gt;) and then we &amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt; the &amp;amp;lt;code&amp;amp;gt;Task&amp;amp;lt;/code&amp;amp;gt; returned by it (&amp;amp;lt;code&amp;amp;gt;sendAll&amp;amp;lt;/code&amp;amp;gt;).&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;If &amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; send&amp;amp;lt;/code&amp;amp;gt; would not have suspended &amp;amp;lt;code&amp;amp;gt;sendAll&amp;amp;lt;/code&amp;amp;gt;, it might have completed immediately, &amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;ed our &amp;amp;lt;code&amp;amp;gt;FinalAwaiter&amp;amp;lt;/code&amp;amp;gt; and we would attempt to resume the calling coroutine, before it has even been stored in the promise, because it was never suspended and &amp;amp;lt;code&amp;amp;gt;await_suspend&amp;amp;lt;/code&amp;amp;gt; has not been called yet!&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;This is why &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;this&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; time, we want to &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;amp;lt;code&amp;amp;gt;std::suspend_always&amp;amp;lt;/code&amp;amp;gt; from &amp;amp;lt;code&amp;amp;gt;initial_suspend&amp;amp;lt;/code&amp;amp;gt;.&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;This also means that when we first &amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt; a &amp;amp;lt;code&amp;amp;gt;Task&amp;amp;lt;/code&amp;amp;gt;, we should resume it once, so it starts executing:&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;cpp&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            &amp;lt;/span&amp;gt;&amp;lt;span style="color: #928374; font-style: italic"&amp;gt;// In Awaiter (returned from operator co_await)&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_suspend(std::coroutine_handle&amp;amp;amp;lt;&amp;amp;amp;gt; continuation) &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;                handle.promise().continuation = continuation;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;                handle.resume();&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            }&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;This also invites us to &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;do&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; something called &amp;amp;amp;ldquo;symmetric transfer&amp;amp;amp;rdquo; in which we can suspend one coroutine and resume another without consuming additional stack space.&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;Read &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;this&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; post by Lewis Baker to learn more: &amp;amp;lt;a href=&amp;lt;/span&amp;gt;&amp;lt;span style="color: #b8bb26"&amp;gt;&amp;amp;quot;https://lewissbaker.github.io/2020/05/11/understanding_symmetric_transfer&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;gt;Understanding Symmetric Transfer&amp;amp;lt;/a&amp;amp;gt;.&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;To use it, we simply have to &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; a coroutine handle from &amp;amp;lt;code&amp;amp;gt;await_suspend&amp;amp;lt;/code&amp;amp;gt; instead of calling &amp;amp;lt;code&amp;amp;gt;resume()&amp;amp;lt;/code&amp;amp;gt; on it:&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;cpp&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            &amp;lt;/span&amp;gt;&amp;lt;span style="color: #928374; font-style: italic"&amp;gt;// In Awaiter (returned from operator co_await)&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_suspend(std::coroutine_handle&amp;amp;amp;lt;&amp;amp;amp;gt; calling) &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;                handle.promise().continuation = calling;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;                &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; handle;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            }&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;We can also use &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;this&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; in &amp;amp;lt;code&amp;amp;gt;FinalAwaiter::await_suspend&amp;amp;lt;/code&amp;amp;gt;:&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;cpp&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;template&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;amp;amp;lt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;typename&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;P&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_suspend(std::coroutine_handle&amp;amp;amp;lt;P&amp;amp;amp;gt; handle) &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; handle.promise().continuation;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        }&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;The &amp;amp;lt;a href=&amp;lt;/span&amp;gt;&amp;lt;span style="color: #b8bb26"&amp;gt;&amp;amp;quot;https://github.com/andreasbuhr/cppcoro&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;gt;cppcoro&amp;amp;lt;/a&amp;amp;gt; library has a &amp;amp;lt;a href=&amp;lt;/span&amp;gt;&amp;lt;span style="color: #b8bb26"&amp;gt;&amp;amp;quot;https://github.com/andreasbuhr/cppcoro/blob/10bbcdbf2be3ad3aa56febcf4c7662d771460a99/include/cppcoro/config.hpp#L33&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;gt;check&amp;amp;lt;/a&amp;amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;for&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; whether a compiler supports symmetric transfer, but judging from my trials on &amp;amp;lt;a href=&amp;lt;/span&amp;gt;&amp;lt;span style="color: #b8bb26"&amp;gt;&amp;amp;quot;https://godbolt.org&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;gt;godbolt&amp;amp;lt;/a&amp;amp;gt; it seems that symmetric transfer works &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;for&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; all compilers that don&amp;amp;amp;rsquo;t complain about their respective C++&amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;20&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; flags (GCC &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;11&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; and later, MSVC &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;19.29&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; and later), so I will just use it.&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;Now that &amp;amp;lt;code&amp;amp;gt;initial_suspend&amp;amp;lt;/code&amp;amp;gt; returns &amp;amp;lt;code&amp;amp;gt;std::suspend_always&amp;amp;lt;/code&amp;amp;gt; our coroutine does not start executing until we &amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt; it, meaning that it would make sense to make our &amp;amp;lt;code&amp;amp;gt;Task&amp;amp;lt;/code&amp;amp;gt; type &amp;amp;lt;code&amp;amp;gt;[[nodiscard]]&amp;amp;lt;/code&amp;amp;gt;, otherwise creating the coroutine would simply &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;do&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; nothing and that is likely a mistake we want to help &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;catch&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;:&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;code&amp;amp;gt;cpp&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #fb4934"&amp;gt;class&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; [[nodiscard]] Task {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #928374; font-style: italic"&amp;gt;// ...&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;};&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;The last tweak we want to make to &amp;amp;lt;code&amp;amp;gt;Task&amp;amp;lt;/code&amp;amp;gt; is to &amp;amp;lt;code&amp;amp;gt;Awaiter::await_ready&amp;amp;lt;/code&amp;amp;gt;. It returns &amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fe8019"&amp;gt;false&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;, which works &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;for&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; our code, but in &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;case&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; the coroutine is already done when we &amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt; it, we don&amp;amp;amp;rsquo;t want to suspend, but rather &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; the value right away:&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;cpp&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;bool&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_ready() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;                &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; !handle || handle.done();&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            }&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;Putting it all together, we get &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;this&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;:&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #282828; background-color: #fb4934"&amp;gt;```&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;cpp&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #fb4934"&amp;gt;class&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; [[nodiscard]] Task {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #fb4934"&amp;gt;public&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;:&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;struct&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;FinalAwaiter&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;bool&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;await_ready&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fe8019"&amp;gt;false&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;; }&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;template&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;amp;amp;lt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;typename&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;P&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_suspend(std::coroutine_handle&amp;amp;amp;lt;P&amp;amp;amp;gt; handle) &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; handle.promise().continuation;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_resume() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;};&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #fb4934"&amp;gt;struct&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;Promise&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    std::coroutine_handle&amp;amp;amp;lt;&amp;amp;amp;gt; continuation;&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    Task &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;get_return_object&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;()&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; Task { std::coroutine_handle&amp;amp;amp;lt;Promise&amp;amp;amp;gt;::from_promise(*&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;this&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;) };&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;unhandled_exception&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;return_void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    std::suspend_always &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;initial_suspend&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {}; }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    FinalAwaiter &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;final_suspend&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {}; }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;};&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #fb4934"&amp;gt;using&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; promise_type = Promise;&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;Task() = &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;default&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;~Task()&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;{&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;if&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (handle_) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        handle_.destroy();&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;}&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #fb4934"&amp;gt;struct&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;Awaiter&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    std::coroutine_handle&amp;amp;amp;lt;Promise&amp;amp;amp;gt; handle;&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;bool&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;await_ready&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; !handle || handle.done(); }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_suspend(std::coroutine_handle&amp;amp;amp;lt;&amp;amp;amp;gt; calling) &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        handle.promise().continuation = calling;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; handle;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;void&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; await_resume() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; { }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;};&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;operator&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;() &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;noexcept&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;{&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; Awaiter { handle_ };&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;}&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;private&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;:&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;explicit&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; Task(std::coroutine_handle&amp;amp;lt;Promise&amp;amp;gt; handle)&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        : handle_(handle)&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;std::coroutine_handle&amp;amp;amp;lt;Promise&amp;amp;amp;gt; handle_;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;};&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #282828; background-color: #fb4934"&amp;gt;``&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;*The &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;final&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;Task&amp;lt;/span&amp;gt;&amp;lt;span style="color: #282828; background-color: #fb4934"&amp;gt;`&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;class&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #8ec07c"&amp;gt;is&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; here: &amp;amp;lt;a href=&amp;lt;/span&amp;gt;&amp;lt;span style="color: #b8bb26"&amp;gt;&amp;amp;quot;https://github.com/pfirsich/aiopp/blob/main/include/aiopp/task.hpp&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;gt;task.hpp&amp;amp;lt;/a&amp;amp;gt;*&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;And here&amp;amp;amp;rsquo;s the application that uses it:&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #282828; background-color: #fb4934"&amp;gt;```&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;cpp&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;Task sendAll(IoQueue&amp;amp;amp;amp; io, &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; Fd&amp;amp;amp;amp; socket, &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; std::string&amp;amp;amp;amp; buffer)&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;{&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;size_t&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; offset = &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;0&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;while&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (offset &amp;amp;amp;lt; buffer.size()) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; [ec, sentBytes]&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            = &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; send(io, socket, buffer.data() + offset,&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;                buffer.size() - offset);&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;if&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (ec) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            spdlog::error(&amp;amp;amp;ldquo;Error in send: {}&amp;amp;amp;rdquo;, ec.message());&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        }&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;if&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (sentBytes == &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;0&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;) { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #928374; font-style: italic"&amp;gt;// Connection closed&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    offset += sentBytes;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;}&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;}&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;BasicCoroutine echo(IoQueue&amp;amp;amp;amp; io, Fd socket)&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;{&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;while&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fe8019"&amp;gt;true&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        std::string recvBuffer(&amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;1024&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;, &amp;amp;amp;lsquo;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #282828; background-color: #fb4934"&amp;gt;\&amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;0&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rsquo;);&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; [ec, receivedBytes]&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            = &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; recv(io, socket, recvBuffer.data(), recvBuffer.size());&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;if&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (ec) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            spdlog::error(&amp;amp;amp;ldquo;Error in receive: {}&amp;amp;amp;rdquo;, ec.message());&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;break&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        }&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;if&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (receivedBytes == &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;0&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;) { &amp;lt;/span&amp;gt;&amp;lt;span style="color: #928374; font-style: italic"&amp;gt;// Connection closed&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;break&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;lt;/span&amp;gt;

&amp;lt;span style="color: #dddddd"&amp;gt;    recvBuffer.resize(receivedBytes);&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; sendAll(io, socket, recvBuffer);&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;}&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;}&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;BasicCoroutine serve(IoQueue&amp;amp;amp;amp; io, Fd&amp;amp;amp;amp;&amp;amp;amp;amp; listenSocket)&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;{&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;while&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fe8019"&amp;gt;true&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;const&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; [ec, fd] = &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;co_await&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; accept(io, listenSocket, &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;nullptr&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;, &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;nullptr&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;);&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;if&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (ec) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            spdlog::error(&amp;amp;amp;ldquo;Error in accept: {}&amp;amp;amp;rdquo;, ec.message());&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;            &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;continue&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        echo(io, Fd { fd });&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;}&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;int&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; main()&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;{&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;auto&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; socket = createTcpListenSocket(IpAddress::parse(&amp;amp;amp;ldquo;&amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;0.0.0.0&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;amp;rdquo;).value(), &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;4242&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;);&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;if&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; (socket == &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;-1&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;) {&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;        &amp;lt;/span&amp;gt;&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;1&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;    }&amp;amp;lt;/p&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;IoQueue io;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;serve(io, std::move(socket));&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;io.run();&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #fb4934"&amp;gt;return&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style="color: #d3869b"&amp;gt;0&amp;lt;/span&amp;gt;&amp;lt;span style="color: #dddddd"&amp;gt;;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span style="color: #dddddd"&amp;gt;&amp;amp;lt;p&amp;amp;gt;}&amp;lt;/span&amp;gt;
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;


&amp;lt;em&amp;gt;The final echo server is here: &amp;lt;a href="https://github.com/pfirsich/aiopp/blob/main/examples/echo-tcp-coro.cpp"&amp;gt;echo-tcp-coro.cpp&amp;lt;/a&amp;gt;&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;h2 id="returning-values-from-coroutines"&amp;gt;Returning Values From Coroutines&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;The final thing that bothers me about this echo server is that when &amp;lt;code&amp;gt;sentBytes&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (the connection has been closed between receiving and sending), we attempt another &amp;lt;code&amp;gt;recv&amp;lt;/code&amp;gt;, which will immediately fail.
Ideally we would return &amp;lt;code&amp;gt;std::pair&amp;amp;lt;std::error_code, bool&amp;amp;gt;&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;sendAll&amp;lt;/code&amp;gt; which contains a potential error and an EOF (&amp;amp;ldquo;end-of-file&amp;amp;rdquo;) flag, so we can return from &amp;lt;code&amp;gt;echo&amp;lt;/code&amp;gt; early, if needed:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;cpp
        const auto [sendEc, eof] = co_await sendAll(io, socket, recvBuffer);
        if (sendEc || eof) {
            break;
        }&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;and:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;```cpp
Task&amp;lt;std::pair\&amp;lt;std::error_code, bool&amp;gt;&amp;gt; sendAll(
    IoQueue&amp;amp;amp; io, const Fd&amp;amp;amp; socket, const std::string&amp;amp;amp; buffer)
{
    size_t offset = 0;
    while (offset &amp;amp;lt; buffer.size()) {
        const auto [ec, sentBytes]
            = co_await send(io, socket, buffer.data() + offset, buffer.size() - offset);
        if (ec) {
            spdlog::error(&amp;amp;ldquo;Error in send: {}&amp;amp;rdquo;, ec.message());
            co_return std::make_pair(ec, false);
        }&amp;lt;/p&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;    if (sentBytes == 0) { // Connection closed
        co_return std::make_pair(ec, true);
    }

    offset += sentBytes;
}
co_return std::make_pair(std::error_code {}, false);
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;p&amp;gt;}
```&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I mentioned earlier that we can define &amp;lt;code&amp;gt;Promise::return_value&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;Promise::return_void&amp;lt;/code&amp;gt; to do that.
And like the continuation earlier, we will store the result in the &amp;lt;code&amp;gt;Promise&amp;lt;/code&amp;gt; as well.
Additionally we have to make &amp;lt;code&amp;gt;Awaiter::await_resume&amp;lt;/code&amp;gt; return our result from the promise, to make the &amp;lt;code&amp;gt;co_await&amp;lt;/code&amp;gt; expression return a result.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;To support arbitrary return types, I have made &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; a template class and to make sure it still works with void, I specialized the &amp;lt;code&amp;gt;Promise&amp;lt;/code&amp;gt; type for &amp;lt;code&amp;gt;Result=void&amp;lt;/code&amp;gt;.
I used &amp;lt;code&amp;gt;requires&amp;lt;/code&amp;gt; expressions to define different &amp;lt;code&amp;gt;Awaiter::await_resume&amp;lt;/code&amp;gt; functions for different Result template arguments.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;This is the whole thing:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;```cpp
template &amp;lt;typename Result = void&amp;gt;
class [[nodiscard]] Task {
public:
    struct FinalAwaiter {
        bool await_ready() const noexcept { return false; }&amp;lt;/p&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;    template &amp;amp;lt;typename P&amp;amp;gt;
    auto await_suspend(std::coroutine_handle&amp;amp;lt;P&amp;amp;gt; handle) noexcept
    {
        return handle.promise().continuation;
    }

    void await_resume() const noexcept { }
};

struct Promise {
    std::coroutine_handle&amp;amp;lt;&amp;amp;gt; continuation;
    Result result;

    Task get_return_object()
    {
        return Task { std::coroutine_handle&amp;amp;lt;Promise&amp;amp;gt;::from_promise(*this) };
    }

    void unhandled_exception() noexcept { }

    void return_value(Result&amp;amp;amp;&amp;amp;amp; res) noexcept { result = std::move(res); }

    std::suspend_always initial_suspend() noexcept { return {}; }
    FinalAwaiter final_suspend() noexcept { return {}; }
};
using promise_type = Promise;

Task() = default;

~Task()
{
    if (handle_) {
        handle_.destroy();
    }
}

struct Awaiter {
    std::coroutine_handle&amp;amp;lt;Promise&amp;amp;gt; handle;

    bool await_ready() const noexcept { return !handle || handle.done(); }

    auto await_suspend(std::coroutine_handle&amp;amp;lt;&amp;amp;gt; calling) noexcept
    {
        handle.promise().continuation = calling;
        return handle;
    }

    template &amp;amp;lt;typename T = Result&amp;amp;gt;
    requires(std::is_same_v&amp;amp;lt;T, void&amp;amp;gt;)
    void await_resume() noexcept { }

    template &amp;amp;lt;typename T = Result&amp;amp;gt;
    requires(!std::is_same_v&amp;amp;lt;T, void&amp;amp;gt;)
    T await_resume() noexcept { return std::move(handle.promise().result); }
};

auto operator co_await() noexcept { return Awaiter { handle_ }; }
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;p&amp;gt;private:
    explicit Task(std::coroutine_handle&amp;lt;Promise&amp;gt; handle)
        : handle_(handle)
    {
    }&amp;lt;/p&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;std::coroutine_handle&amp;amp;lt;Promise&amp;amp;gt; handle_;
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;p&amp;gt;};&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;template &amp;amp;lt;&amp;amp;gt;
struct Task&amp;lt;void&amp;gt;::Promise {
    std::coroutine_handle&amp;amp;lt;&amp;amp;gt; continuation;&amp;lt;/p&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;Task get_return_object()
{
    return Task { std::coroutine_handle&amp;amp;lt;Promise&amp;amp;gt;::from_promise(*this) };
}

void unhandled_exception() noexcept { }

void return_void() noexcept { }

std::suspend_always initial_suspend() noexcept { return {}; }
FinalAwaiter final_suspend() noexcept { return {}; }
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;p&amp;gt;};
&amp;lt;code&amp;gt;``
*The&amp;lt;/code&amp;gt;Task` class is here: &amp;lt;a href="https://github.com/pfirsich/aiopp/blob/main/include/aiopp/task.hpp"&amp;gt;task.hpp&amp;lt;/a&amp;gt;*&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;You may ask if we should have or could have extended our &amp;lt;code&amp;gt;BasicCoroutine&amp;lt;/code&amp;gt; to handle return values as well, but we would have to change so much about it, that the name would not be justified anymore and we would almost have &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; anyways but without &amp;lt;code&amp;gt;operator co_await&amp;lt;/code&amp;gt;.
We would have to make &amp;lt;code&amp;gt;final_suspend&amp;lt;/code&amp;gt; return &amp;lt;code&amp;gt;std::suspend_always&amp;lt;/code&amp;gt; as well, so the coroutine frame lives long enough for us to get the result from the &amp;lt;code&amp;gt;Promise&amp;lt;/code&amp;gt; through the &amp;lt;code&amp;gt;BasicCoroutine&amp;lt;/code&amp;gt; object.
And then we couldn&amp;amp;rsquo;t use it anymore to &amp;amp;ldquo;branch off&amp;amp;rdquo; with &amp;lt;code&amp;gt;echo&amp;lt;/code&amp;gt; because it returns a temporary and now that the &amp;lt;code&amp;gt;BasicCoroutine&amp;lt;/code&amp;gt; object has ownership of the coroutine, it would be destroyed in &amp;lt;code&amp;gt;~BasicCoroutine&amp;lt;/code&amp;gt;.
So we still have reasons to keep a type without a non-void return value, like &amp;lt;code&amp;gt;BasicCoroutine&amp;lt;/code&amp;gt;, around.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Also now that we have a &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; class that owns the coroutine, it is possible that we destroy it (by destroying the &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;) when it still has queued IO operations that essentially keep a reference to our &amp;lt;em&amp;gt;awaiter&amp;lt;/em&amp;gt; (in the lambda capture). To avoid a use-after-free, it is necessary to cancel IO operations if the &amp;lt;em&amp;gt;awaiter&amp;lt;/em&amp;gt; being referenced in the &amp;lt;code&amp;gt;IoQueue&amp;lt;/code&amp;gt; dies. I did not include that in this tutorial yet, because I haven&amp;amp;rsquo;t figured out how to do that nicely myself. Maybe I&amp;amp;rsquo;ll edit it into this blog post in the future or maybe you figure it out and let me know if you find something that works well for you.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="where-to-go-next"&amp;gt;Where To Go Next&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;Lastly I have to mention that if you want to do anything multi-threaded or if you want to handle exceptions, there is extra work you have to do and you have to be a lot more careful everywhere.
I&amp;amp;rsquo;m not going to do that here.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Although I might have (sort of) figured out how to use coroutines, I don&amp;amp;rsquo;t really have experience with writing larger programs (beyond simple echo servers).
It&amp;amp;rsquo;s possible that some of the solutions I have presented here might just be very annoying or problematic if used in larger code bases.
I hope I get a chance and the inspiration to write about this in a later blog post.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="tips"&amp;gt;Tips&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;My number one, huge, seriously golden tip: &amp;lt;strong&amp;gt;use &amp;lt;a href="https://github.com/google/sanitizers/wiki/AddressSanitizer"&amp;gt;AddressSanitizer&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;.
It&amp;amp;rsquo;s very easy to build coroutine programs that use-after-free or leak memory without you realizing.
I wholeheartedly suggest to turn on ASan and not turn it off again, as long as you are messing around with coroutines.
At some point every code you write compiles, lots of it works and the only one telling you it&amp;amp;rsquo;s completely wrong is ASan.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;To help me understand which functions are called when and when objects are destroyed, I added logging to all objects on creation/destruction/copy with something like this: &amp;lt;a href="https://gist.github.com/pfirsich/e5e2c43ef8816f40bb8029ac8f7fb54a"&amp;gt;DebugLogging&amp;lt;/a&amp;gt;.
I also added logs to every magic method - all the &amp;lt;code&amp;gt;await_*&amp;lt;/code&amp;gt;s and all the &amp;lt;code&amp;gt;Promise&amp;lt;/code&amp;gt; methods.
It might seem silly dumping so many logs, but it really helps a lot to get an understanding of the control flow and I definitely needed it to get any understanding of coroutines in C++.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="sources"&amp;gt;Sources&amp;lt;/h2&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://lewissbaker.github.io/"&amp;gt;Asymmetric Transfer&amp;lt;/a&amp;gt; - Lewis Baker&amp;amp;rsquo;s blog. It&amp;amp;rsquo;s very detailed and it felt a bit overwhelming to me at the beginning, but it leaves few open questions and is a great read if you already sort of know how coroutines work.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://github.com/andreasbuhr/cppcoro"&amp;gt;cppcoro&amp;lt;/a&amp;gt;. The de-facto helper library for coroutines in C++. The link points to a fork, which seems to be more maintained than the original repository by Lewis Baker, who seems to really know their coroutines.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://en.cppreference.com/w/cpp/language/coroutines"&amp;gt;Coroutines on cppreference&amp;lt;/a&amp;gt;. Everyone knows this website is good, but this particular site is more helpful than I would have thought.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="https://pabloariasal.github.io/2022/11/12/couring-1/"&amp;gt;C++20 Coroutines and io_uring&amp;lt;/a&amp;gt;. I tried working with coroutines a few times and just got confused without ever really getting anywhere. This helped me get started more than any other resource and I modeled my post after it. I just tried to go a bit further in some directions and explain some things that did not get clear to me reading that blog post.&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;</content>
    </entry>
    
    <entry>
        <title>Why Is There No Invisible Database?</title>
        
        <link href="https://joelschumacher.de/posts/why-is-there-no-invisible-database"/>
        <id>https://joelschumacher.de/posts/why-is-there-no-invisible-database</id>
        <updated>2023-04-19T21:09:09+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;In this post I&amp;amp;rsquo;ll write about the exploration of an old idea of mine, which didn&amp;amp;rsquo;t lead very far, so it might not be the most informative piece. If you have time to spare, go ahead. This will also serve as a reminder to myself when I revisit the idea in a few years.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="the-idea"&amp;gt;The Idea&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;For a few years I have been thinking about a database that requires little to no explicit storage and loading. I imagined simply marking a &amp;lt;code&amp;gt;std::vector&amp;lt;/code&amp;gt; for example as &amp;amp;ldquo;in the database&amp;amp;rdquo; and it would all just magically happen. I wouldn&amp;amp;rsquo;t have to create wrapper classes and or write tedious serialization/deserialization code. Most developer dislike writing plumbing code, right? I wanted a system that automatically retrieves the newest version whenever I access a data structure and sends a modified version back to the server, when I modify it. And ideally it would work with arbitrary data structures, without any extra work. Something like this:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;```cpp
struct TestStruct {
    std::string str;
    unsigned int num;
};&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;// You need some sort of key, so you can identify that vectors across
// different machines belong together.
InTheDatabase&amp;lt;std::vector\&amp;lt;TestStruct&amp;gt;&amp;gt; vec(&amp;amp;ldquo;vec&amp;amp;rdquo;);&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;vec-&amp;amp;gt;push_back(TestStruct { &amp;amp;ldquo;Joel&amp;amp;rdquo;, 69 /&amp;lt;em&amp;gt;nice&amp;lt;/em&amp;gt;/ });
// &amp;amp;ldquo;Joel&amp;amp;rdquo; is now in &amp;amp;ldquo;vec&amp;amp;rdquo; and available on every connected client machine&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;// This might print a bunch of &amp;lt;code&amp;gt;str&amp;lt;/code&amp;gt;s, that we did not put into &amp;amp;ldquo;vec&amp;amp;rdquo;,
// but another client might have put there
for (const auto&amp;amp;amp; elem : *vec) {
    fmt::print(&amp;amp;ldquo;{}: {}\n&amp;amp;rdquo;, elem.str, elem.num);
}
```&amp;lt;/p&amp;gt;
&amp;lt;h2 id="the-missing-piece"&amp;gt;The Missing Piece&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;Intuitively I thought that &amp;lt;code&amp;gt;InTheDatabase&amp;lt;/code&amp;gt; would somehow inject a custom allocator that would track all dynamic allocations the type might be doing and keep track of that memory.
It seemed to me the biggest problem would be detecting all modifications done to these tracked memory ranges. And because there was no way to do something like that (there is), I never really spent much time on the idea.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Then, a few days ago, I learned about the &amp;amp;ldquo;&amp;lt;code&amp;gt;PROT_NONE/SIGSEGV&amp;lt;/code&amp;gt; trick&amp;amp;rdquo;.
It involves using &amp;lt;a href="https://man7.org/linux/man-pages/man2/mprotect.2.html"&amp;gt;mprotect&amp;lt;/a&amp;gt; to change the access protections of a range of memory to &amp;lt;code&amp;gt;PROT_NONE&amp;lt;/code&amp;gt; (for this use case &amp;lt;code&amp;gt;PROT_READ&amp;lt;/code&amp;gt; would work too), which disallows any accesses and installing a signal handler for SIGSEGV, which would be triggered whenever the protected region would be accessed.
You could then detect these memory accesses and note down the page that was accessed and restore the access protections to whatever you had before (probably &amp;lt;code&amp;gt;PROT_READ | PROT_WRITE&amp;lt;/code&amp;gt;).
This was my missing piece (&amp;lt;em&amp;gt;so I thought&amp;lt;/em&amp;gt;)! Maybe I could use this to implement my invisible database?!
Shortly (seconds actually) after that I learned, that there is also &amp;lt;a href="https://www.kernel.org/doc/html/latest/admin-guide/mm/userfaultfd.html"&amp;gt;userfaultfd&amp;lt;/a&amp;gt;, which is a Linux feature that is dedicated to detecting page-faults in user space in a clean way, which can do this as well in a &amp;amp;ldquo;proper and more optimal&amp;amp;rdquo; way.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="a-revised-sketch"&amp;gt;A Revised Sketch&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;This idea made me engage with this invisible database more seriously. The first thing I realized is that in order to maintain invariants of the classes being stored in the database, we have to introduce transactions. If we simply synchronize every modified memory region as soon as we can, we can easily bring data structures into invalid states. Data structures may also span multiple pages (esp. if they do many allocations) or cross page boundaries. For example if we &amp;lt;code&amp;gt;push_back&amp;lt;/code&amp;gt;-ed an element into a vector, we might update the size first and then actually allocate the new element (which might be on a different page). Of course it could be the other way around as well, which would be better for us, but we should not rely on implementation details we cannot control (or sometimes even know) to maintain valid data structures. Very similar to multi-threaded programming, you have to protect the integrity (invariants) of these data structures with some sort of mutex. This invites the introduction of another abstraction of a memory region in which we can place as many data structures as we want and that we can lock and unlock to modify it transactionally:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;```cpp
// the last argument is region size in pages
invisibledb::SyncedMemoryRegion region(server, &amp;amp;ldquo;region&amp;amp;rdquo;, 4);&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;struct TestStruct {
    std::pmr::string str;
    unsigned int num;
};&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;// This will lock the region on the server preventing any other client
// from locking it for a while, and read the current version from the server.
// It might also actually lock a mutex, so you can use the SyncedMemoryRegion
// from multiple threads.
region.lock();
const auto vec = region.getObject&amp;lt;std::pmr::vector\&amp;lt;TestStruct&amp;gt;&amp;gt;(&amp;amp;ldquo;vec&amp;amp;rdquo;);
// Here we will send all modified pages to the server and the region will be unlocked.
region.unlock();&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;// &amp;amp;hellip;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;region.lock()
vec-&amp;amp;gt;push_back(TestStruct { &amp;amp;ldquo;Joel&amp;amp;rdquo;, 42 });&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;for (const auto&amp;amp;amp; elem : *vec) {
    fmt::print(&amp;amp;ldquo;{}: {}\n&amp;amp;rdquo;, elem.str, elem.num);
}
region.unlock();
```&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;There are also some other small changes in this snippet. To inject the allocator, we used the standard library types from the &amp;lt;code&amp;gt;std::pmr&amp;lt;/code&amp;gt; (polymorphic memory resource) namespace. Also of course we need some object that represents the database server, &amp;lt;code&amp;gt;server&amp;lt;/code&amp;gt;, which we need to pass into the &amp;lt;code&amp;gt;SyncedMemoryRegion&amp;lt;/code&amp;gt;. Where it comes from, how we connect and anything like that is not important for our sketch. The &amp;lt;code&amp;gt;getObject&amp;lt;/code&amp;gt; factory function either creates the vector on the heap, inside the memory region or returns the instance, if an object with that name is already in the region. It was already like that in the first sketch, but it should be mentioned that the vector itself must not live on the stack, or it would not be synchronized properly (duh).&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Additionally because we can track memory accesses already, we can do cool things like &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt;ing when the memory is accessed without the region being locked, because sometimes that&amp;amp;rsquo;s the only way they&amp;amp;rsquo;re gonna learn.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Note that it&amp;amp;rsquo;s very easy to be less than extremely careful here and use the wrong allocator by accident. For example like this:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;cpp
std::pmr::string str = "Joel";
vec-&amp;amp;gt;push_back(TestStruct { std::move(str), 42 });&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Here the &amp;lt;code&amp;gt;str&amp;lt;/code&amp;gt; field in our &amp;lt;code&amp;gt;TestStruct&amp;lt;/code&amp;gt; object is &amp;lt;strong&amp;gt;not&amp;lt;/strong&amp;gt; allocated in the memory region managed by the database!
That&amp;amp;rsquo;s a very easy mistake, hard to catch and the behavior exhibited will be maddeningly weird. Bad sign.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Also we need to consider that the allocator for the &amp;lt;code&amp;gt;SyncedMemoryRegion&amp;lt;/code&amp;gt; will have to keep it&amp;amp;rsquo;s state inside the memory region as well. That means all variables that control the allocator behavior have to be inside this memory region and have to be synchronized. Otherwise we might allocate from the start of the region multiple times on different clients and overwrite things by accident. For that reason alone we have to roll our own allocator (or multiple, depending on use case). But there is also another, smaller reason, which is that we require perfectly predictable allocator behavior. This almost gives us no other choice but to roll our own. Imagine that on one client an allocator might reuse a previously deallocated region and on another client a different allocator (maybe from a different standard library implementation) might reuse another. A more practical reason is also, is that the pmr containers keep a pointer to the allocator, which of course should not point outside the synchronized memory region as well.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;And thinking about this it also becomes clear that not just all the allocators have to have the same behavior, but all the data structures involved to. So to be sure, you probably want to use &amp;lt;strong&amp;gt;exactly&amp;lt;/strong&amp;gt; the same standard library version for each client. A small corollary, which might be even more obvious, is that we cannot mix little and big endian clients. That might be a bit too restrictive to be useful.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="the-prototype"&amp;gt;The Prototype&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;This is about where I started implementing this thing. If you were smarter than me, you might have figured this out before starting, but pretty much all the interesting data structures have pointers. And even though they will point into the synchronized memory region, if you do everything right, those addresses might (very likely) not be correct on other clients, because the base address of the memory region will be different on different clients. I could not figure out how to fix this properly, except by walking through the whole modified memory region and finding everything that is aligned like a pointer and contains a value that looks like a pointer (i.e. an address inside of this memory region). After finding those addresses, I make them relative, save their offsets and restore them with the proper base address on reception. Yes, this could give false positives, which should be unlikely, but would lead to the most confusing bugs.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;You can check out my proof-of-concept implementation here: &amp;lt;a href="https://github.com/pfirsich/invisibledb"&amp;gt;pfirsich/invisibledb&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;In my implementation I took some shortcuts for the first (and likely last) prototype. The &amp;lt;code&amp;gt;Server&amp;lt;/code&amp;gt; object does not actually connect anywhere and &amp;lt;code&amp;gt;Server::sendPage&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Server::receivePage&amp;lt;/code&amp;gt; simply &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; some memory to and from a buffer. Similarly &amp;lt;code&amp;gt;Server::lockRegion&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Server::unlockRegion&amp;lt;/code&amp;gt; simply set a boolean flag. The &amp;lt;code&amp;gt;TrackedMemoryRegion&amp;lt;/code&amp;gt; class, which was supposed to do the cool stuff - tracking writes using &amp;lt;code&amp;gt;usefaultfd&amp;lt;/code&amp;gt; - currently only uses &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; to check whether a page was modified. I wanted to keep the complexity low whereever possible until I implemented the tricky bits. That turned out to be wise, because, as I have explained above, they were very tricky.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Also the allocator is a very simple linear allocator that can not reuse freed memory and simply increases an offset from which it gives out memory. In a real world application you definitely want something smarter and likely different allocators for different use cases and data structures. You would possibly need to support multiple different allocators in the same region.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Of course there are a couple more ways to improve this, which are not really relevant at the level of seriousness of this project.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="conclusion"&amp;gt;Conclusion&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;Now that I have finally implemented a (not so) invisible database, I know why it didn&amp;amp;rsquo;t exist before or at least why it&amp;amp;rsquo;s not very popular. It was tricky to build and a fun exercise, but there are some downsides to using it, which are the answer to &amp;amp;ldquo;Why is there no invisible database?&amp;amp;rdquo;:&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;Visiblity: The resulting system is not nearly as invisible as we would like it to be (explicit locking, specific ways of creating objects, &amp;amp;hellip;).&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Usability (arguably still &amp;amp;ldquo;visibility&amp;amp;rdquo;): It&amp;amp;rsquo;s extremely easy to misuse and the resulting bugs are very confusing. Having a variable on the stack, forgetting to inject the right allocator or forgetting to lock the region, etc. can cause significant headaches.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Performance: While you do save the serialization/deserializion logic there is significant overhead. Intercepting every memory access is likely inefficient. As is the scanning of memory for pointer-like values during synchronization. There are probably some access patterns where it might be faster than any other database, but I cannot come up with them and I definitely did not prove it.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Portability: You cannot mix clients with different endianness or even standard library versions and maybe even compilers. And, of course, &amp;lt;code&amp;gt;userfaultfd&amp;lt;/code&amp;gt; is currently limited to Linux only! You can only use it with C or C++ and those languages are not considered very cool or 🚀 blazingly fast 🚀 anymore. Even if you use exactly the same software on every client, you probably want to upgrade at some point. Since you are storing memory regions, an ABI break in some library you use might break your weekend.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Complexity: Despite ignoring many complications (a real server, proper allocators, proper write tracking), the resulting piece of software is quite the monstrosity and I am sure you can measure my heart rate increase, when I look at it. Introducing complexity usually implies future costs.&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;p&amp;gt;And even if any of these are no concern to you, you don&amp;amp;rsquo;t really know if it will stay like that forever. I would not feel comfortable introducing something like this into my project. Even if I had made it!&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;If we finally (ever?) get reflection in C++, another approach might be to generate serialization/deserialization logic for &amp;lt;a href="https://en.wikipedia.org/wiki/Passive_data_structure"&amp;gt;POD&amp;lt;/a&amp;gt;s and provide some wrappers for standard library classes to simply interface with any of the popular databases. This would essentially be just a fancy client library for an existing database. And if we ever do get reflection, I will probably try that.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Expectedly my idea did not lead to a groundbreaking conclusion, but I found it very worthwile to explore this topic more deeply and the better I understand the remaining problems, the more likely I am to find solutions for them in the future.&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>Ray Casting in 2D Grids</title>
        
        <link href="https://joelschumacher.de/posts/ray-casting-in-2d-grids"/>
        <id>https://joelschumacher.de/posts/ray-casting-in-2d-grids</id>
        <updated>2016-02-10T21:21:48+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;Ray casting is used in many different areas of game development, most commonly for visibility, AI (often for visibility though) and collision detection and resolution. If you are making a game, chances are you need ray casting somewhere. I started this blog post over a year ago, but decided to not write it up fully and publish it, since I thought that it might be a little embarassing, since most if it is too trivial. But I still find it fairly hard to find any good information or example code on this and on the weekend of Global Game Jam 2016, I forgot how to do it properly and didn&amp;amp;rsquo;t find any good resources on this, ending up debugging ray casting code for a little over 3 hours (unnecessarily, I think). So if this actually helps no one then this shall remain as a memorial of shame for myself. Or as a handy reminder, so history does not repeat itself in a way that leaves me debugging ray casting code for hours.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The relevancy of grids is given by the prevalence of tile based games and even if the game is not tile based, because of optimization structures for collision detection/physics or other gameplay elements that are often in place, being either directly (simple uniform grids) or indirectly (e.g. quadtrees) related to grids.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Throughout this article, our grid will be a uniform grid with cell size &amp;lt;code&amp;gt;grid.cellSize&amp;lt;/code&amp;gt;.
The ray will be a tuple of a point (it&amp;amp;rsquo;s origin) and a vector (it&amp;amp;rsquo;s direction), namely &amp;lt;code&amp;gt;ray.startX, ray.startY&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ray.dirX, ray.dirY&amp;lt;/code&amp;gt;. The set of points on the ray is then described by: &amp;lt;code&amp;gt;{ray.start + t*ray.dir | t is a real number}&amp;lt;/code&amp;gt; and we can &amp;amp;ldquo;address&amp;amp;rdquo; every point on the ray with a value &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;All methods presented here on out are implemented in this GitHub repository (rather badly most of the time, since I started this project over a year ago so this is a little patchwork-ey, but I put some work into refactoring, so it should be bearable):&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="https://github.com/pfirsich/ray-casting-test"&amp;gt;https://github.com/pfirsich/ray-casting-test&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;h2 id="the-naive-method"&amp;gt;The Naive Method&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;The simplest, but often times an adequate way to do it, is stepping uniformly in world coordinates. In our case, where our ray direction is not normalized, we can not just step uniformly in &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt;, but must use our normalized direction vector multiplied by the step size (again: in world coordinates).&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Even if often times this is sufficient, it is never perfect in the sense that this method finds all cells that intersect with the ray and with finite dt, there will always be corners that could be overstepped. An example of this from the example löve program (function &amp;lt;code&amp;gt;castRay_naive&amp;lt;/code&amp;gt;) can be seen in this screenshot:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="/images/naive_ray_casting.png"&amp;gt;&amp;lt;img alt="Naive Ray Casting" src="/images/naive_ray_casting.png" title="Naive Ray Casting" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The boxes inside the cells indicate missing or superfluous cells.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Of course this method could be &amp;amp;ldquo;exact&amp;amp;rdquo; if we always choose the step size to be corresponding to the size of a single pixel on screen, meaning we would not be able to distinguish exact and inexact at this point, but this would imply a huge number of samples, which is most likely not efficient enough.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="line-rasterization-methods-eg-dda-bresenham"&amp;gt;Line Rasterization Methods (e.g. &amp;lt;a href="https://en.wikipedia.org/wiki/Digital_differential_analyzer_%28graphics_algorithm%29"&amp;gt;DDA&amp;lt;/a&amp;gt;, &amp;lt;a href="https://en.wikipedia.org/wiki/Bresenham's_line_algorithm"&amp;gt;Bresenham&amp;lt;/a&amp;gt;)&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;This might seem like the obvious choice and depending on your game (or the problem at hand) it might very well be, but in general this is also not sufficient, since these algorithms operate in (in our case) tile coordinates only, so that there will be no difference in a ray connecting the upper left corner of a tile and the lower right of another tile and a ray connecting the lower right corner of the same, first tile and the upper left corner of the other one. In fact most commonly line rasterization algorithms will rasterize every pixel, when a diamond shape in the pixel&amp;amp;rsquo;s center intersects the line connecting the centers of the start and end pixel (the &amp;amp;ldquo;diamond rule&amp;amp;rdquo;). An example of this, including a visualization of the diamonds mentioned before, can be found in this screenshot (also from the example program, which has both DDA and Bresenham available):&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="/images/ray_casting_bresenham.png" title="Ray Casting with Line Rasterization - Bresenham"&amp;gt;&amp;lt;img alt="Ray Casting with Line Rasterization - Bresenham" src="/images/ray_casting_bresenham.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Here you can see that we lose the information of where exactly inside the tile our start and end points are and also don&amp;amp;rsquo;t treat the the tiles as axis aligned squares.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;If you just need &amp;lt;em&amp;gt;any&amp;lt;/em&amp;gt; line connecting your start and endpoint somehow, you might use a line rasterization method since they can be implemented very efficiently - and probably already have been, since they are so important for computer graphics in general. Also if your game has everything snapping to the tile grid and everything centered, this becomes an exact solution (a modern example would be Crypt of the Necrodancer)!&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;In my example program the functions implementing this are called &amp;lt;code&amp;gt;castRay_DDA&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;castRay_Bresenham&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="exact-ray-casting"&amp;gt;Exact Ray Casting&amp;lt;/h2&amp;gt;
&amp;lt;h3 id="simplified-case-direction-positive"&amp;gt;Simplified Case (direction positive)&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;In a more (algorithmically) efficient method we would love to not visit cells twice, i.e. make no unnecessary steps and never miss anything. So if you want to find all intersections of the line with the grid and don&amp;amp;rsquo;t miss any, at every step of the algorithm, you just have to find the first one, given your current position and direction.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="/images/ray_casting_tile.png" title="Ray Casting a Tile"&amp;gt;&amp;lt;img alt="Ray Casting a Tile" src="/images/ray_casting_tile.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;If we consider the current position &amp;lt;code&amp;gt;curX, curY&amp;lt;/code&amp;gt;, we can easily find the the tile coordinates of the tile &amp;lt;code&amp;gt;curX, curY&amp;lt;/code&amp;gt; is in by dividing by the cell size and truncating the floating point part. Beware that, because we are using Lua for example code (since the example program is in Lua), arrays and tiles will be 1-indexed, i.e. start with index 1. So we will have to add 1 to both tile coordinates to get the final coordinate:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;lua
function tileCoords(cellSize, x, y)
  return math.floor(x / cellSize) + 1, math.floor(y / cellSize) + 1
end&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;To get the next edges (assuming our direction is positive in x and y direction), we only have to add &amp;lt;code&amp;gt;grid.cellSize&amp;lt;/code&amp;gt;, or in our cases, since we already added 1, do nothing but transform back to world coordinates, by multiplying with &amp;lt;code&amp;gt;grid.cellSize&amp;lt;/code&amp;gt;. The distance to these edges can then be divided by the corresponding components of our direction vector to give us these distances in units of &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt;!&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;lua
local tileX, tileY = tileCoords(grid.cellSize, curX, curY)
local dtX = ((tileX)*grid.cellSize - curX) / ray.dirX
local dtY = ((tileY)*grid.cellSize - curY) / ray.dirY&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;To find the &amp;lt;strong&amp;gt;first&amp;lt;/strong&amp;gt; intersection, we then only have to increment our current &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt; by the smaller &amp;lt;code&amp;gt;dt&amp;lt;/code&amp;gt; of the two and update our current position.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Implemented as the function &amp;lt;code&amp;gt;castRay_clearer_positive&amp;lt;/code&amp;gt;, the results are exactly what we wanted!&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="/images/ray_casting_accurate.png" title="Ray Casting - Accurate"&amp;gt;&amp;lt;img alt="Ray Casting - Accurate" src="/images/ray_casting_accurate.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Though, as mentioned before, negative directions (any axis) still give us some problems:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="/images/ray_casting_negative.png" title="Ray Casting Negative - Problems!"&amp;gt;&amp;lt;img alt="Ray Casting Negative - Problems!" src="/images/ray_casting_negative.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The reasons for this are obviously our flawed calculation for the next edge, since in the current case, we add 1 to the tile coordinates. In the negative cases, we would have to add zero, since the edges we want to hit are the ones of the current tile.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;This is intentionally formulated to hint at the other problem, which is that if we jump to the next intersection, we will still be in the current tile and revisit the first intersection indefinitely! This is because &amp;lt;code&amp;gt;math.floor&amp;lt;/code&amp;gt; maps values from &amp;lt;code&amp;gt;[x, x+1)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt;, so that a whole integer maps to itself, which is very sensible for a floor function, but is not entirely what we want.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="complete-case-all-directions"&amp;gt;Complete Case (all directions)&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;The problem of finding the next edge is trivial to solve, by introducing an offset of the tile coordinates that depends on the direction:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;```lua
&amp;amp;ndash; NOTE: &amp;amp;lsquo;cond and x or y&amp;amp;rsquo; is a common idiom that is mostly equivalent to the
&amp;amp;ndash; ternary operator i.e. equals x if cond evaluates to true and y otherwise
local dirSignX = ray.dirX &amp;amp;gt; 0 and 0 or -1
local dirSignY = ray.dirY &amp;amp;gt; 0 and 0 or -1&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;amp;hellip;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;local dtX = ((tileX + dirSignX)&amp;lt;em&amp;gt;grid.cellSize - curX) / ray.dirX
local dtY = ((tileY + dirSignY)&amp;lt;/em&amp;gt;grid.cellSize - curY) / ray.dirY
```&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The &amp;lt;code&amp;gt;floor&amp;lt;/code&amp;gt;-problem has multiple ways to solve it. One would be to rewrite our floor function so that it takes an additional parameter, which indicates which side of the interval should be open (i.e. not include the integer). Another one is to add an epsilon to our &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt;, when incrementing it by either &amp;lt;code&amp;gt;dtX&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;dtY&amp;lt;/code&amp;gt;, so that we will barely sneak into the next cell. Choosing this epsilon is a little tricky though since by introducing it, our algorithm will start to have edges it could overstep, just like the naive method. Any non-vanishing epsilon will have this as a result and even if we make it really small (of the order of a screen pixel size), we might run into issues when it just disappears because of floating point normalization, when ray casting in really big grids. This method might then resemble a naive method, with a really small step, which intelligently skips some samples, if possible.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The best way though would probably be to introduce our own tile coordinates, which are not calculated from the current position, but kept track of alongside it. Then we can just decide to increment/decrement these at the right times - &amp;lt;code&amp;gt;tileX&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;dtX &amp;amp;amp;lt; dtY&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tileY&amp;lt;/code&amp;gt; otherwise. This is implemented in the function &amp;lt;code&amp;gt;castRay_clearer_alldirs_improved&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;h2 id="final-solution"&amp;gt;Final Solution&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;The hawkeye programmer might have noticed that our &amp;lt;code&amp;gt;castRay_clearer_alldirs_improved&amp;lt;/code&amp;gt; is a little more complicated than it should be. You have to watch a little more closely but some terms in the calculation of &amp;lt;code&amp;gt;dtX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;dtY&amp;lt;/code&amp;gt; might be constant and maybe we can eliminate the division. In fact we can and with a little more transforms and noticing that all our constants are symmetric in x and y, so that we might as well write a helper function that calculates these independent of axis, we arrive at our new function &amp;lt;code&amp;gt;castRay_clearer_alldirs_improved_transformed&amp;lt;/code&amp;gt; (thank god this article is going to end soon, these names are getting long). The necessary transformations to arrive at this function are shown in the following images:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The unmodified version of &amp;lt;code&amp;gt;castRay_clearer_alldirs_improved&amp;lt;/code&amp;gt;:
&amp;lt;a href="/images/raycast_trafo_1.png" title="Ray Casting Function Transformation #1"&amp;gt;&amp;lt;img alt="Ray Casting Function Transformation #1" src="/images/raycast_trafo_1.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The part with the central logic is replaced so the actual modification of the central variables happens outside. This is so we can identify the delta of &amp;lt;code&amp;gt;dtX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;dtY&amp;lt;/code&amp;gt; more easily:
&amp;lt;a href="/images/raycast_trafo_2.png" title="Ray Casting Function Transformation #2"&amp;gt;&amp;lt;img alt="Ray Casting Function Transformation #2" src="/images/raycast_trafo_2.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Again we simplify to ease the identification of the delta of &amp;lt;code&amp;gt;dtX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;dtY&amp;lt;/code&amp;gt; by wirting the change in &amp;lt;code&amp;gt;curX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;curY&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;dt&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt;:
&amp;lt;a href="/images/raycast_trafo_3.png" title="Ray Casting Function Transformation #3"&amp;gt;&amp;lt;img alt="Ray Casting Function Transformation #3" src="/images/raycast_trafo_3.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Here we &amp;amp;ldquo;pull out&amp;amp;rdquo; the first assignment of &amp;lt;code&amp;gt;dtX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;dtY&amp;lt;/code&amp;gt; and only apply deltas in the main loop of the algorithm, which can be identified by subtracting the &amp;lt;code&amp;gt;dtX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;dtY&amp;lt;/code&amp;gt; of two successive iterations:
&amp;lt;a href="/images/raycast_trafo_4.png" title="Ray Casting Function Transformation #4"&amp;gt;&amp;lt;img alt="Ray Casting Function Transformation #4" src="/images/raycast_trafo_4.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;At this point we don&amp;amp;rsquo;t need &amp;lt;code&amp;gt;curX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;curY&amp;lt;/code&amp;gt; anymore and can just put it into our mark-function, which is only used for visualization:
&amp;lt;a href="/images/raycast_trafo_5.png" title="Ray Casting Function Transformation #5"&amp;gt;&amp;lt;img alt="Ray Casting Function Transformation #5" src="/images/raycast_trafo_5.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;To simplify further, we prepare by putting all assignments after the if into the cases, so that we can optimize them separately and for their special cases):
&amp;lt;a href="/images/raycast_trafo_6.png" title="Ray Casting Function Transformation #6"&amp;gt;&amp;lt;img alt="Ray Casting Function Transformation #6" src="/images/raycast_trafo_6.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;We just plug in the known values of &amp;lt;code&amp;gt;dtileX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;dtileY&amp;lt;/code&amp;gt; and reorder a little:
&amp;lt;a href="/images/raycast_trafo_7.png" title="Ray Casting Function Transformation #7"&amp;gt;&amp;lt;img alt="Ray Casting Function Transformation #7" src="/images/raycast_trafo_7.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Now we use that all intermediate variables defined at the top are symmetric in x and y and can be calculated by a common function. We also take out the division from the main loop, since the summand is constant through all iterations (&amp;lt;code&amp;gt;ddtX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ddtY&amp;lt;/code&amp;gt;) and rename &amp;lt;code&amp;gt;dirSignX&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;dirSignY&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;dtileX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;dtileY&amp;lt;/code&amp;gt;:
&amp;lt;a href="/images/raycast_trafo_8.png" title="Ray Casting Function Transformation #8"&amp;gt;&amp;lt;img alt="Ray Casting Function Transformation #8" src="/images/raycast_trafo_8.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;One branch and 5 additions per step and a setup function (a little trickier though, but constant time) is probably as good as it can get, though it is definitely not as apparent what is actually happening in this function. If we decide that we have no use for t and therefore the intersection points themselves (and just want to visit some cells, or want to know if there is a possible path at all), then we can eliminate t all together and because we don&amp;amp;rsquo;t care about the actual values of dtX and dtY, we can decide to omit the &amp;amp;ldquo;&amp;lt;code&amp;gt;- dt&amp;lt;/code&amp;gt;&amp;amp;rdquo; term, because the comparison in the next iteration will still yield the same result, so that our algorithm would be reduced to one branch and two additions. This is in fact the algorithm described in &amp;lt;a href="http://www.cse.yorku.ca/~amana/research/grid.pdf"&amp;gt;&amp;amp;ldquo;A Fast Voxel Traversal Algorithm for Ray Tracing&amp;amp;rdquo;&amp;lt;/a&amp;gt; by John Amanatides and Andrew Woo, which inspired the transformations done to &amp;lt;code&amp;gt;castRay_clearer_alldirs_improved&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;All in all, I showed you what the problems of ray casting in 2D grids are and what kind of solutions for them exists or seem to exist, but turn out to be a fluke. And also made a nice connection to another algorithm, which many use without understanding it properly, by deriving it from an easier to understand one and applying some transformations.&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>Preparation for Indie Speed Run 2015 - Screwdriver, SparklEd, Lighting</title>
        
        <link href="https://joelschumacher.de/posts/isr2015-preparation-screwdriver-sparkled-lighting"/>
        <id>https://joelschumacher.de/posts/isr2015-preparation-screwdriver-sparkled-lighting</id>
        <updated>2015-11-06T01:35:12+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;In preparation for Indie Speed Run 2015 (which went well and for which I will post our game when the voting period starts) me and a long time programming buddy, &amp;lt;a href="http://shellfishgames.com/"&amp;gt;Markus&amp;lt;/a&amp;gt;, decided to prepare by building a handful of tools that are going to make some things a little easier. We find ourself discarding the same ideas time and time again, because we don&amp;amp;rsquo;t deem them feasible in the often severly limited amount of time or not discarding them but spending too much time on them, so we decided to prepare them beforehand.
We had a lot of stuff in mind including a post-process library, realtime and precomputed 2D lighting, pre-built character controllers and smooth collision detection and response solutions for different scenarios that we might need, finally a proper particle system and a corresponding editor, an editor and a library for skeletal animations, and a level editor that supplements the awesome &amp;lt;a href="http://www.mapeditor.org/"&amp;gt;Tiled&amp;lt;/a&amp;gt; for games that are not tile based (but either polygon or simply sprite based). But as it becomes glaringly obvious this is quite a lot of work and of course we did not manage to finish everything we had on the list, although still a considerable part of it.
Markus worked on the animation editor/library and manged to finish it in time. Sadly we didn&amp;amp;rsquo;t have any use for it in the jam, just as we didn&amp;amp;rsquo;t for everything I worked on. We wanted to implement the best idea we had and coincidentally (and unexpectedly) there was no need for the tech we developed beforehand (exluding a small exception elaborated on later). The projects I took on and managed to finish mostly before the jam were the lighting system, the particle effect editor and the level editor.&amp;lt;/p&amp;gt;
&amp;lt;h2&amp;gt;The Level Editor (Screwdriver) - &amp;lt;a href="https://github.com/pfirsich/Screwdriver"&amp;gt;GitHub&amp;lt;/a&amp;gt;&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;This level editor uses my GUI, kraidGUI. It&amp;amp;rsquo;s a GUI made for being modified in a sense. It only serves as a slim core for handling/passing events and handling properties. Look and feel are implemented in a &amp;amp;ldquo;theme&amp;amp;rdquo;, which makes use of a very simple backend, which, as of yet, is only implemented for löve. Every part of it can be exchanged and extended easily. For Screwdriver I had to implement and color picker and was surprised how well kraidGUI did it&amp;amp;rsquo;s work by making this very easy.
Both the GUI and the Editor were meant as an exercise in writing actual software. I feel like, lacking a formal education and professional experience, I tend to &amp;amp;ldquo;make things work&amp;amp;rdquo; first and foremost often leaving proper software design behind. This certainly also has a lot to do with me participating in game jams a lot. But GUIs and Editors (in this case especially) are meant to be used a lot more than once. kraidGUI has some things I&amp;amp;rsquo;m still not completely content with and Screwdriver is also not free from a few sketchy ways to do things, that I would consider hacks, but all in all I think that it&amp;amp;rsquo;s still mostly quite readable, maintainable and hack free. Both of them lack documentation, but I think it&amp;amp;rsquo;s very common for programmers to not be particularly fond of creating these. Anyways I will try to still spend some time on documenting kraidGUI soon, since I think it&amp;amp;rsquo;s a nice piece of software and other people might deem it useful too.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Regarding the editor itself, I made it for usage with many different games in mind. Every type of entity in the game world has an entity description, which contains Metadata (modifiable or not), so a seemingly fairly custom fitted editor can be prepared for any game without much effort. The system corresponding to the components that make up the entities are implemented in the components itself, which kind of defeats the purpose of ECSs, since special cases still have to be handled inside the components, but the editor was supposed to be modular and capable of being extended with rather complicated edit modes without treating the main components special. Therefore I&amp;amp;rsquo;m borrowing terminology more than anything from entity component systems. Thankfully I didn&amp;amp;rsquo;t regret the way of doing this yet, since there was no special case except shared behaviour that could be resolved by properly breaking up functionality and using inheritance. The editor remains very modular and can be extended fairly easily with rather comprehensive editing capabilities.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;An example of such a entity description file can be seen here (and should be self-explanatory):&amp;lt;/p&amp;gt;
&amp;lt;script src="https://gist.github.com/pfirsich/4e9e7fb9bf626e3085d4.js"&amp;gt;&amp;lt;/script&amp;gt;

&amp;lt;p&amp;gt;The editor itself can be seen used in this video:&amp;lt;/p&amp;gt;
&amp;lt;iframe width="560" height="315" src="https://www.youtube.com/embed/x0ldw3uBklg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;

&amp;lt;h2&amp;gt;The Particle Effect Edtior (SparklEd) - &amp;lt;a href="https://github.com/pfirsich/SparklEd"&amp;gt;GitHub&amp;lt;/a&amp;gt;&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;After collecting some notes about the particle system I wanted to implement for this editor, I remembered briefly that I might have heard of löve having a particle system already. I didn&amp;amp;rsquo;t check, but a properly tested system that is potentially a lot more efficient (instancing, geometry shaders) should be preferred to anything I could implement in löve itself. So I could reduce the amount of work I had to do to making an editor for löve&amp;amp;rsquo;s partice system.
I made the editor in a day plus a few days fixing bugs while using it. I borrowed the idea of using the mousewheel for numeric value editing to reduce the amount of GUI related work (didn&amp;amp;rsquo;t want to bloat a project that small with kraidGUI). Using the mousewheel while hovering a property reduces/increases it, while holding shift decreases the amount of change. Loading is done by using the mousewheel above a property (serving as a radio button) and saving via shortcut. It supports multiple emitters to make many-layered effects (explosions for example need smoke, debris, fire, etc.). It supports continuous effects (e.g. fire) and bursted effects (you can press space to emit &amp;amp;ldquo;Emit amount&amp;amp;rdquo; of particles). And has a brief built-in documentation in the form of tooltips. It can be seen used in this video:&amp;lt;/p&amp;gt;
&amp;lt;iframe width="560" height="315" src="https://www.youtube.com/embed/FxFmrirFCmA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;

&amp;lt;h2&amp;gt;Lighting&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;When I started on this I was very short on time, so I had to make some suboptimal decisions. I would probably do a lot of things differently if I had to do it again, so I will not go into much detail. Every light in the world has an own lightmap (normally a lot smaller than the in-game pixels it affects, because of the soft shadows that alleviate a lof of these visual impact of lower resolution lightmaps), which is only update if the light or if the occluders the light affects change (if it throws shadows). I also implemented soft shadows by appending fins to the shadow geometry on both sides and scaling them appropriately.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Hard Shadows, 1 Light:
&amp;lt;a href="/images/lighting_hard_shadows_1_light.png"&amp;gt;&amp;lt;img alt="Hard Shadows, 1 Light" src="/images/lighting_hard_shadows_1_light.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Soft Shadows, 1 Light:
&amp;lt;a href="/images/lighting_soft_shadows_1_light.png"&amp;gt;&amp;lt;img alt="Soft Shadows, 1 Light" src="/images/lighting_soft_shadows_1_light.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Hard Shadows, 11 Lights:
&amp;lt;a href="/images/lighting_hard_shadows_11_lights.png"&amp;gt;&amp;lt;img alt="Hard Shadows, 11 Lights" src="/images/lighting_hard_shadows_11_lights.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Soft Shadows, 11 Lights:
&amp;lt;a href="/images/lighting_soft_shadows_11_lights.png"&amp;gt;&amp;lt;img alt="Soft Shadows, 11 Lights" src="/images/lighting_soft_shadows_11_lights.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>Old Videos Fixed</title>
        
        <link href="https://joelschumacher.de/posts/old-videos-fixed"/>
        <id>https://joelschumacher.de/posts/old-videos-fixed</id>
        <updated>2015-03-10T16:24:42+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;Some of you may have noticed, that most of the posts tagged with &amp;amp;ldquo;from old blog&amp;amp;rdquo; have broken videos. It turns out that it is not super easy to get a high quality video from unpublished blogspot blog posts (that&amp;amp;rsquo;s what I did with my old blog), but I managed to find most of the old ones.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The following posts now have proper videos and I encourage you to watch them in their full HD glory:&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="http://theshoemaker.de/2013/04/spacewalk-part-1/"&amp;gt;Spacewalk&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="http://theshoemaker.de/2013/12/metroidlike-2d-water-bone-animations-catching-up-part-1/"&amp;gt;Metroidlike&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href="http://theshoemaker.de/2013/01/feedback-effect/"&amp;gt;Feedback-Effect&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;p&amp;gt;Also I found videos of a few demoscene-related things I started when I was a little younger. I never really participated in the demoscene, but was a long time admirer and of course tried to do similar stuff myself, but the results were rather lame. One of these things is an attempt at a 4KB intro, which you can see here:&amp;lt;/p&amp;gt;
&amp;lt;iframe width="560" height="315" src="https://www.youtube.com/embed/NIl6jnO0uYE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;

&amp;lt;p&amp;gt;In retrospect I think it&amp;amp;rsquo;s quite neat and I probably should have finished it. But I felt a little intimidated and inadequate next to these things:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="http://www.pouet.net/prodlist.php?type[0]=4k&amp;amp;amp;page=1&amp;amp;amp;order=views"&amp;gt;pouet.net - 4k - sorted by popularity&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>SudoHack update &amp; Replay system</title>
        
        <link href="https://joelschumacher.de/posts/sudohack-update-replay-system"/>
        <id>https://joelschumacher.de/posts/sudohack-update-replay-system</id>
        <updated>2015-03-08T14:21:34+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;So I really have to write another blog post. 120 of the 173 total commits for my Git repository have been after the last blog post and I start to feel bad about putting anything new in the game, because I should have documented all the other stuff already.&amp;lt;/p&amp;gt;
&amp;lt;h2&amp;gt;SudoHack update&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;Notably I started putting my &amp;lt;a href="https://gist.github.com/pfirsich/56fc805d9ca7ea62f645"&amp;gt;Changelog online&amp;lt;/a&amp;gt;, drastically changed the game once, should have posted about it and changed it again. I am currently in the process of changing it another time. The first drastic change was losing your Bits a lot faster over time and gaining a lot more for every enemy kill. This essentially meant that you could not stand still or not kill enemies without dying, which was a lot closer to my creative vision I had from the start. I started feeling rather confident with the game and received good feedback, but I realized: to make a full fledged game out of it that offers the scope that I had in mind, I had to make a lot more levels. Taking in to account that the player only sees a subset of all the possible levels in every run, I estimated I had to make about 300 maps. In conjunction with the fact that it took me a least a week to make 6 I kind of liked, I had to take a different approach if I ever want to finish it (which is one of the main goals of this project), prompting the second radical change. So I revisited the two level generators I already started working on and dismissed pretty fast. And like always you just have to throw enough sweat and man hours at something to make something work and I arrived at something I rather like at the moment.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Screenshots:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="/images/sudohack_level_generator_1.png"&amp;gt;&amp;lt;img src="/images/sudohack_level_generator_1.png" alt="SudoHack Level Generator Example #1" height="240"/&amp;gt;&amp;lt;/a&amp;gt;
&amp;lt;a href="/images/sudohack_level_generator_2.png"&amp;gt;&amp;lt;img src="/images/sudohack_level_generator_2.png" alt="SudoHack Level Generator Example #2" height="240" /&amp;gt;&amp;lt;/a&amp;gt;
&amp;lt;a href="/images/sudohack_level_generator_3.png"&amp;gt;&amp;lt;img src="/images/sudohack_level_generator_3.png" alt="SudoHack Level Generator Example #3" height="240" /&amp;gt;&amp;lt;/a&amp;gt;
&amp;lt;a href="/images/sudohack_level_generator_4.png"&amp;gt;&amp;lt;img src="/images/sudohack_level_generator_4.png" alt="SudoHack Level Generator Example #4" height="240" /&amp;gt;&amp;lt;/a&amp;gt;
&amp;lt;a href="/images/sudohack_level_generator_5.png"&amp;gt;&amp;lt;img src="/images/sudohack_level_generator_5.png" alt="SudoHack Level Generator Example #5" height="240" /&amp;gt;&amp;lt;/a&amp;gt;
&amp;lt;a href="/images/sudohack_level_generator_6.png"&amp;gt;&amp;lt;img src="/images/sudohack_level_generator_6.png" alt="SudoHack Level Generator Example #6" height="240" /&amp;gt;&amp;lt;/a&amp;gt;
&amp;lt;a href="/images/sudohack_level_generator_7.png"&amp;gt;&amp;lt;img src="/images/sudohack_level_generator_7.png" alt="SudoHack Level Generator Example #7" height="240" /&amp;gt;&amp;lt;/a&amp;gt;
&amp;lt;a href="/images/sudohack_level_generator_8.png"&amp;gt;&amp;lt;img src="/images/sudohack_level_generator_8.png" alt="SudoHack Level Generator Example #8" height="240" /&amp;gt;&amp;lt;/a&amp;gt;
&amp;lt;a href="/images/sudohack_level_generator_9.png"&amp;gt;&amp;lt;img src="/images/sudohack_level_generator_9.png" alt="SudoHack Level Generator Example #9" height="240" /&amp;gt;&amp;lt;/a&amp;gt;
&amp;lt;a href="/images/sudohack_level_generator_10.png"&amp;gt;&amp;lt;img src="/images/sudohack_level_generator_10.png" alt="SudoHack Level Generator Example #10" height="240" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The algorithm is essentially a random walk in 2D (a little more fancy than that, but not too fancy) and as you can see in the limit of many steps we can observe a gaussian distribution (as expected with a random walk)! I just put them in to show that this algorithm works rather nicely for small maps (they are very similar to the ones I have built myself) and also quite okay for the medium sized ones.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;With being able to have maps that are a little bigger than the ones before, I could, of course, not resist and also changed the scale of the maps a little. Sadly though I fairly quicky lost the stupid grin I acquired after implementing feature after feature and seeing the simulation time per frame steadily sticking at about 1ms. Apparently things aren&amp;amp;rsquo;t always O(1) and sometimes even worse than O(n). But that&amp;amp;rsquo;s why I kept a tidy list of any optimizations I could do if need ever be in my Trello, which I honestly couldn&amp;amp;rsquo;t even wait to tackle.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;A lot of the collision was optimized by only checking collision with the level geometry for the tile the object is currently on and surrounding tiles, but player-enemy and enemy-enemy collision never had a broadphase detection step, which I then implemented. After considering numerous approaches and comparing the necessary gain with the amount of work required I settled with the easiest solution, which is a grid/spatial hash. The whole grid effect was re-tweaked and optimized for only being applied to a little more than the visible tiles. Also other parts of the collision detection were optimized a little, I replaced a lot of &amp;lt;em&amp;gt;if shape.type == &amp;amp;ldquo;whatever&amp;amp;rdquo;&amp;lt;/em&amp;gt; with table lookups, which proved to be exceptionally better. But I don&amp;amp;rsquo;t even know why I didn&amp;amp;rsquo;t do it from the start, since the code also got a lot smaller and prettier by doing it. It seems like I reached the point where I grew out of the code I wrote during the beginning of the project, meaning that I know more about the language now and get shivers running down my spine reading the early stuff. Also I implemented collision detection filtering for &amp;amp;ldquo;idle&amp;amp;rdquo; objects and enemy AI is now divided between &amp;amp;ldquo;thinking&amp;amp;rdquo; and &amp;amp;ldquo;acting&amp;amp;rdquo;. The former here represents the current state (and substate) of the enemy and it&amp;amp;rsquo;s transitions between them, usually involving the more costly computations (ray casts, a lot of distance calculations) and the latter the behaviour, mostly consisting of accelerating towards something or shooting players (outrageous!).&amp;lt;/p&amp;gt;
&amp;lt;h2&amp;gt;Replay system&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;Something I spent a lot more time on than I should have is definitely gameplay recordings. I can&amp;amp;rsquo;t spend a 40 hour week (or more) on this game and I certainly don&amp;amp;rsquo;t have huge testing capacities, so I wanted to maximize the information I could get from the few testers I have.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;As far as I see it, there are two fundamental approaches to doing this:&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;
    &amp;lt;li&amp;gt;recording user input and just "playing it back" afterwards&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;recording snapshots of the whole game state and relevant events&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;As far as my analysis went the pros for each method are as follows:&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;
    &amp;lt;li&amp;gt; State snapshots
&amp;lt;ul&amp;gt;
    &amp;lt;li&amp;gt;will work even if you're simulation isn't deterministic, therefore less error prone considering differing floating point behaviour for different architectures (and potentially different binaries). But most networked games already have this requirement and deterministic simulations can be achieved without bending over backwards.&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;probably smaller if the dimension of your state space is rather small (few enemies, bullets, etc.)
&amp;lt;ul&amp;gt;
    &amp;lt;li&amp;gt;Also you can choose arbitrary precision for most of your recorded data. It is not important that the player looks exactly in the direction it did while recording if it looks good enough, while it can be dangerous to truncate precision with keypress recording.&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;a lot less dependent on mini-tweaks. Changing a value a little in enemy behaviour might lead to digressions that eventually destroy the recording&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;you can record only a few seconds in the middle of the game without knowing the full history. This could also be done with keypress-recording but you would have to make a full state snapshot at the start, which is almost half the work of doing it completely with state snapshots.&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Rewinding and seeking are relatively easy to implement. Using keystrokes this is only possible with making snapshots every N frames and skipping to them.&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Keypresses
&amp;lt;ul&amp;gt;
    &amp;lt;li&amp;gt;probably smaller if the dimension of your state space is rather high (only a few inputs for potentially thousands of enemies/bullets)&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;could potentially be coded once and reused for multiple projects (modulo extra meta data), given your simulations are always deterministic&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;can be 'stapled on' later rather easily (again, determinism provided)&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;could be used as a tool to reproduce bugs that are often difficult to produce&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;the user can be recorded in the menu or during the pause screen and observing unwanted keypresses (the user trying out different keys because she/he doesn't know how something is supposed to work) or just how well the user can navigate those menus is essentially for free (but also mandatory). In essence: unwanted behaviour or behaviour not specifically expected might be observed, which is a useful tool for debugging.&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Gives you another reason to use a fixed timestep, which you definitely should (for framerate independent behaviour/making sure that approximation in the integrator is valid for the used dt, because physics might get weird with too small or too big dt/because it's crucial for networked multiplayer), though in-between frame interpolation might be needed.&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;p&amp;gt;In this case I thought that for my purpose, which is not actual ingame replay of something that is visible to the player but rather a being tool for me, the Keypress recording should be my method of choice. My implementation is Open Source an can be found here:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="https://github.com/pfirsich/loveDemoLib"&amp;gt;loveDemoLib&amp;lt;/a&amp;gt; (see main.lua for a usage example)&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;My googling showed (I could have made a histogram or something and tested it myself) that regular gamepads mostly have a precision of 10-12 Bit for every axis, so I tried using fixed precision for these floats by writing &amp;lt;em&amp;gt;floor(val*GAMEPAD_AXIS_FP_PREC)&amp;lt;/em&amp;gt; and reading &amp;lt;em&amp;gt;val/GAMEPAD_AXIS_FP_PREC&amp;lt;/em&amp;gt;. Apparently &amp;lt;em&amp;gt;GAMEPAD_AXIS_FP_PREC&amp;lt;/em&amp;gt; being 10^5 - 1 or 10^6 - 1 is still enough to throw the simulation off rather quickly. I assume this is because of binning problems e.g. non-homogeneous density of float numbers in the interval -1 to 1 in contrast to homogeneous density of fixed point numbers in this interval, so that some fixed point numbers correspond to multiple floats and some to none.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Also I really wanted to implement binary writing, but it is far too much of a hassle in Lua if you want to write numbers (extracting every byte yourself for integers and mantissa/exponent for floats). It&amp;amp;rsquo;s certainly not inconceivably hard, but considering that I wrote the uploader in Python, zipping the file before uploading guarantees that the file to upload is seldom bigger than 1MB, which is in this day and age totally acceptable, I think.&amp;lt;/p&amp;gt;
&amp;lt;h4&amp;gt;Integration&amp;lt;/h4&amp;gt;
&amp;lt;p&amp;gt;First I added a pre-commit to my git repository that calls a Python script which then replaced certain variables in my code. For now it&amp;amp;rsquo;s just a timestamp of the commit (I would really like to have a hash, but I can&amp;amp;rsquo;t get the hash of the commit before commiting of course and later commiting the changed file is also suboptimal) so I can (almost) uniquely identify different versions of the game and can always checkout the necessary version to play back a specific recording.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Then I added an awesome duo of an uploader, written in Python:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="/images/sudohack_demo_uploader.png"&amp;gt;&amp;lt;img alt="SudoHack Demo Uploader" src="/images/sudohack_demo_uploader.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;and a Web interface for adding keys and overviewing and downloading the recordings uploaded by the testers (also I love Bootstrap):&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="/images/sudohack_demo_webinterface_1.png"&amp;gt;&amp;lt;img alt="SudoHack Demo Web Interface 1" src="/images/sudohack_demo_webinterface_1.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="/images/sudohack_demo_webinterface_2.png"&amp;gt;&amp;lt;img alt="SudoHack Demo Web Interface 2" src="/images/sudohack_demo_webinterface_2.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="/images/sudohack_demo_webinterface_3.png"&amp;gt;&amp;lt;img alt="SudoHack Demo Web Interface 3" src="/images/sudohack_demo_webinterface_3.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;They are far from great and there is a lot of stuff I would change if I could justify putting any more work into them, but the only people that will ever use them are probably people I personally know quite well, so I don&amp;amp;rsquo;t feel super bad about it.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Of course I also did a bit of other stuff in 120 commits, but I want to write them up in a later blog post with a little more context (and screenshots and videos of course).&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>Tweaking Values in SudoHack</title>
        
        <link href="https://joelschumacher.de/posts/tweaking-values-in-sudohack"/>
        <id>https://joelschumacher.de/posts/tweaking-values-in-sudohack</id>
        <updated>2015-02-22T19:00:44+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;It is fairly known that just tweaking values in a game a few percent can make or break awesome gameplay and create the difference between an iconic franchise and the joy of gameplay you often get from games that are made by some 13-year olds and uploaded for testing on a game developement board. Not that I don&amp;amp;rsquo;t like games by 13 year olds, just that it took me a ridiculously long time to get the basic hang of making games remotely fun (I&amp;amp;rsquo;m still very far from being good it). And let&amp;amp;rsquo;s face it: if you are a game developer and you&amp;amp;rsquo;re tweaking the friction that is applied to the player when the boss knocks him back using his extra-power-attack, you often stop after 20 minutes and call it a day. It&amp;amp;rsquo;s tedious and even if it that&amp;amp;rsquo;s not always the case, it is seldom any fun. Especially with a game like SudoHack I discover a new game almost every day by just trying out different parameter spaces for all the configuration values in it.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Until this morning, for every value I wanted to tweak, I had to make changes in the code and restart the game to view it&amp;amp;rsquo;s effects. There &amp;lt;em&amp;gt;was&amp;lt;/em&amp;gt; a system in place, which let me press ctrl+r, generating a tweaks.lua-configuration file (it looked something like this: &amp;lt;a href="https://gist.github.com/pfirsich/854145171298f3175ecf"&amp;gt;https://gist.github.com/pfirsich/854145171298f3175ecf&amp;lt;/a&amp;gt;) and giving me the opportunity to change these values, hit ctrl+r again and have the changes show up in the game in real time. Even though this is almost neat, it is way too complicated to have actually been used (like once or twice maybe). I remember having something like this in one of the dozen C++ game engines I started developing, when I was a little younger, where I would define a &amp;lt;code&amp;gt;TWEAK(value)&amp;lt;/code&amp;gt; macro, which would use &amp;lt;code&amp;gt;__FILE__&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;__COUNTER__&amp;lt;/code&amp;gt; to uniquely identify every call of this macro. The actual implementation would look up the key-pair and upon triggering a reload (by pressing ctrl+r for example) parse all the source files for all occurences of &amp;lt;code&amp;gt;TWEAK&amp;lt;/code&amp;gt; and update it&amp;amp;rsquo;s values, therefore giving me the opportunity to tweak everything in the source and only tell the game to reload the tweaks. And I thought it was awesome. So I set out to do something like this in Lua/löve. The first implementation worked fairly quickly using the already introduced tweak(defaultValue, name) functions all over the code, I update the values by parsing the source for these function calls. Because I fear that it might not fully be clear what I&amp;amp;rsquo;m actually doing with this, here is an example work flow:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;lua
-- &amp;amp;lt;implement new feature (for example: bit rendering)&amp;amp;gt;
love.graphics.setColor(tweak(40, "bits: colR"),
                       tweak(150, "bits: colG"),
                       tweak(200, "bits: colB"),
                       255)
-- &amp;amp;lt;change the values in the source code, while leaving the game running&amp;amp;gt;
love.graphics.setColor(tweak(255, "bits: colR"),
                       tweak(100, "bits: colG"),
                       tweak(100, "bits: colB"),
                       255)
-- &amp;amp;lt;hit ctrl+r&amp;amp;gt;
-- =&amp;amp;gt; The changes are visible in the game&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;This is already pretty neat, but one might think: disregarding potential future uses, why do you even need names? Isn&amp;amp;rsquo;t the nth-occurence of a tweak()-function call and the source file enough to uniquely identify the values? And you&amp;amp;rsquo;re right, they are actually quite useless, but if you have a look at my implementation:&amp;lt;/p&amp;gt;
&amp;lt;script src="https://gist.github.com/pfirsich/51a5a51543da40a3c2fa.js"&amp;gt;&amp;lt;/script&amp;gt;

&amp;lt;p&amp;gt;Then you might formulate this problem as: can we generate the tweak-value names ourselves? And the answer is: I don&amp;amp;rsquo;t know. I asked in #lua on freenode and people recommended me looking at the lua debug module, which has the capability of building a stacktrace at any point in the file, getting the source file name and the current executed line number, but this is not enough if you want to allow multiple tweak values in a single line.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I implemented a package loader, which will be invoked if another module is required in a source file that replaces every occurence of a specific &amp;lt;code&amp;gt;func()&amp;lt;/code&amp;gt;-call with &amp;lt;code&amp;gt;func(x)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt; is the filename and the number of occurences before it concatenated in a string. For the interested:&amp;lt;/p&amp;gt;
&amp;lt;script src="https://gist.github.com/pfirsich/549fc8cb38949feef665.js"&amp;gt;&amp;lt;/script&amp;gt;

&amp;lt;p&amp;gt;Despite it working I don&amp;amp;rsquo;t really feel comfortable using it, since I don&amp;amp;rsquo;t like changing the actual entry point off my game to a different file, only to have it be included right after the tweak-loader. Especially if what I gain seems minimal. Also I really don&amp;amp;rsquo;t like messing with things like this, since love&amp;amp;rsquo;s filesystem sandbox might make this a little more complicated if it is run from a zip-archive (which is, in a shipped version, the default mode of operation), but I&amp;amp;rsquo;m not entirely sure about this.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Finally I will just use the system that was in place today 5 hours ago and see how much entering names will annoy me pretending that they might have an actual use in the future. All the approaches discussed here are, of course, only actually usable in small teams or, more concretely, teams where everyone, who should have the possibility of tweaking game values, knows her/his way around the code. Otherwise a system where code and data are more separated is probably the way to go, since the amount of overhead can be justified with expanding the access to configuration values. Also in that case I would really like some Quake/Source engine like console, which makes easy changes in the game possible and gives the opportunity to spawn graphical elements like sliders/spindowns to edit them visually. For me though, the edit-quick and almost no-overhead solution is more desirable.&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>Exam Preparation Avoidance Game Jam</title>
        
        <link href="https://joelschumacher.de/posts/exam-preparation-avoidance-game-jam"/>
        <id>https://joelschumacher.de/posts/exam-preparation-avoidance-game-jam</id>
        <updated>2015-02-19T17:28:57+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;Last week &amp;lt;a title="Jonas Lieb" href="http://www.jonas-lieb.de/"&amp;gt;Jonas&amp;lt;/a&amp;gt; and I knew that we had to start preparing for our upcoming condensed matter physics exam. Instead we jammed a little game, which should initially only take up one single day of our time, but actually took two. It&amp;amp;rsquo;s a blatant copy of this game: &amp;lt;a href="http://www.bildspielt.de/tipps/fluglotsen-training-fur-jeden-airport-madness-3-109441/"&amp;gt;Attention, German!&amp;lt;/a&amp;gt; Copying games is really interesting and it&amp;amp;rsquo;s always fun figuring out how you can implement something, while maybe even improving it a little or at least giving it a bit of your own twist. I could go on more about this, but I actually just want to keep this blog more complete than comprehensive and actually interesting. If someone will ever read this and maybe even contemplates contacting me about something, then please do so without hesitation. Until then:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Screenshot:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="/images/fluglotse_screenshot.png"&amp;gt;&amp;lt;img alt="Screenshot - Game" src="/images/fluglotse_screenshot.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Editor Screenshot (No actual graphical interface, just a plethora of keyboard shortcuts, a &amp;amp;ldquo;command line&amp;amp;rdquo; and only about 3-4 hours of work):&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="/images/fluglotse_editor_screenshot.png"&amp;gt;&amp;lt;img alt="Screenshot - Editor" src="/images/fluglotse_editor_screenshot.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Video:&amp;lt;/p&amp;gt;
&amp;lt;iframe src="https://www.youtube.com/embed/jN1GjQzoKJM" width="560" height="315" frameborder="0" allowfullscreen="allowfullscreen"&amp;gt;&amp;lt;/iframe&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;a href="https://github.com/jojonas/fluglotse"&amp;gt;Github link&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="http://download.theshoemaker.de/Fluglotse/"&amp;gt;Downloads&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Don&amp;amp;rsquo;t expect it to be particularly fun. It was way more fun to make than it is to play it.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>Global Game Jam 2015 - &#34;Falling Nukes + Running People&#34;</title>
        
        <link href="https://joelschumacher.de/posts/global-game-jam-2015-falling-nukes-running-people"/>
        <id>https://joelschumacher.de/posts/global-game-jam-2015-falling-nukes-running-people</id>
        <updated>2015-01-28T22:49:58+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;Last weekend my notorious partner in crime, &amp;lt;a href="http://jonas-lieb.de/"&amp;gt;Jonas Lieb,&amp;lt;/a&amp;gt; his artist friend Lukas and I attended the Global Game Jam 2015 in Cologne. After watching the keynote, which was not only slightly cringeworthy and partly in a language no one on the site could understand, but also way too long and obviously tinted by Anita Sarkeesian ideology (she was also listed in the section for &amp;amp;ldquo;Special Thanks&amp;amp;rdquo;) the theme was announced as &amp;amp;ldquo;What do we do know?&amp;amp;rdquo;I initially expected something way to artsy and narrow, like one could expect from the GGJ organizers, but I was very pleasantly surprised. My first idea was making a game with no objective, similar to Proteus, but local mulitplayer and, of course, 2D, but somehow one of the guys had the idea of a game, which was also explorative, but rather a quest of finding something specific rather than finding anything. We decided to make a game in which the players are placed into a world with an obvious threat, initially during brainstorming referred to as a comet, but later implemented as the impending impact of nuclear missiles. It is then the players&amp;amp;rsquo; objective to find a way out of this situation by exploring his/her surroundings and finding a way to escape the impending death. We planned on placing numerous different items in the world, which only had capacity for a single player, therefore leaving the rest of the group behind posing the theme question and giving the rest of the team the incentive to step up their efforts. The first major dispute was about the underlying tech of the game either being tile based and only featuring full tiles (i.e. squares) or (my stand point) using arbitrary polygons, which would be edited in a editor specifically made for this game and full images for the whole map rendered above these polygons (which were used for collision). Of course this is a very crude approach and far from efficient, but it was the easiest way this could have been done without major preparatory work. The reason for me rooting for the polygon approach was the fact that, for the first time, we could facilitate having an actual artist who knows what he&amp;amp;rsquo;s doing and leave him a lot of freedom in designing the levels and all the layers above and below it. Jonas though was of the opinion that a tile based approach was not just a lot easier to implement and was something we did numerous times before, but also gave us the opportunity to create levels a lot faster, without Lukas being the obvious bottleneck of the level creation progress. Of course he was right, but I always prefer trying to make a cool game people will find cool rather than doing something mediocre, that will more probably pan out successful. Thankfully Lukas was on my side and we went with the fancy approach.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;After about 24 hours (without any sleep by the way, because I really can&amp;amp;rsquo;t sleep well if I really want to work on something) we had most of the engine running, a test level and could try out a first prototype of the game we had in mind. Quickly we noticed that our idea was flawed in a way or not feasible in such a short amount of time because it seemed way to easy to find a way out, since the objects were clearly stood out as special/objects to interact with. It would have needed a lot more objects, which were actually useless. And we think this wouldn&amp;amp;rsquo;t have changed the feel of the game to an explorative one, but rather to a game which is full of useless stuff, you have to filter out by mashing the &amp;amp;ldquo;use&amp;amp;rdquo; button. We didn&amp;amp;rsquo;t want that and were trapped in a kind of design bubble. I started integrating a little &amp;amp;ldquo;shove&amp;amp;rdquo;-mechanic which pushed and stunned the player for a short period of time and after testing it we noticed that this is probably the most fun element of the game so far and decided we should focus on it. We then made the decision to shift the game into a lot more competitive platformer, with a lot of punching and maybe other fighting mechanics and a lot more linear levels, that forced the players to initiate confrontations trying to reach the escapes. Sadly this sounds as stereotypical and bland as it gets but it was a lot more fun than our previous ideas would have been, I think (at least if we only had 48 hours to invest). The final result can be seen here:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="http://globalgamejam.org/2015/games/falling-nukes-running-people"&amp;gt;Falling Nukes + Running People&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;All in all I am very satisfied with the result. The crowd seemed to like the game and the testers had a lot of fun beating up each other with a little timer in the upper right corner. I&amp;amp;rsquo;m also very happy that technically it turned out a lot easier than Jonas expected. Also as a very nice side effect another jammer might have joined our ranks. And even better: an (in my opinion very competent) artist!&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;As a conclusion to the GGJ this year I learned that it is very important for multiple team members to clearly state their goals in making a game to ensure to make the right decisions along the way (unfortunately this was a little problem in our group, as we discovered afterwards).&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Also I should spend a little time (Hah! &amp;amp;ldquo;little&amp;amp;rdquo;&amp;amp;hellip;) to work on a proper animation editor, since Lukas uttered some dislike in having to draw numerous frames for a single character. At first I thought about a bone animation editor, like &amp;lt;a title="Metroidlike &amp;amp;amp; 2D-Water &amp;amp;amp; Bone-Animations – Catching up Part 1" href="http://theshoemaker.de/2013/12/metroidlike-2d-water-bone-animations-catching-up-part-1/"&amp;gt;the one I started for Metroidvania&amp;lt;/a&amp;gt;, but I&amp;amp;rsquo;d much prefer a hybrid like in the beginning of this video: &amp;lt;a href="https://www.youtube.com/watch?v=y-chi097uV4"&amp;gt;Youtube: How Rayman Legends is Made&amp;lt;/a&amp;gt;. Furthermore I really miss the collision detection library I&amp;amp;rsquo;m planning to make once I have time to finally get rid of the bullet through paper problem, that also proved to be quite annoying during the global game jam. But first: exams, not screwing up my Bachelor&amp;amp;rsquo;s and SudoHack.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>New Website!</title>
        
        <link href="https://joelschumacher.de/posts/new-website"/>
        <id>https://joelschumacher.de/posts/new-website</id>
        <updated>2015-01-20T15:51:39+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;I&amp;amp;rsquo;m using wordpress on a new webspace now. This is the result! Wohoo! Because googling &amp;lt;a title="my name" href="http://en.wikipedia.org/wiki/Joel_Schumacher"&amp;gt;my name&amp;lt;/a&amp;gt; will never result in anything related to me, I &amp;lt;em&amp;gt;had to&amp;lt;/em&amp;gt; choose this domain.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I&amp;amp;rsquo;ll be participating in the global game jam this weekend and will surely inaugurate this website properly shortly after it and when I find time, I will make a short &amp;amp;ldquo;projects&amp;amp;rdquo; page with a little overview of the stuff I&amp;amp;rsquo;ve done. But what will probably take a while.&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>SudoHack - Bits, AI, Weapons, Movement and a Lot More Prettiness</title>
        
        <link href="https://joelschumacher.de/posts/sudohack-bits-ai-prettiness"/>
        <id>https://joelschumacher.de/posts/sudohack-bits-ai-prettiness</id>
        <updated>2015-01-13T16:07:00+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;SudoHack is a multiplayer roguelike  where you and your friends, playing as computer programs, try to infiltrate a computer system. You gain &amp;amp;ldquo;Bits&amp;amp;rdquo; by destroying the guardian programs that are put in your way, but also lose them for every hit you take and every second that passes by. Your goal is to reach the end of the room before you run out of Bits and get destroyed yourself,  therefore gaining access to deeper levels of the system, until you reach the core.&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;So this week really has been rather productive (sadly just regarding SudoHack.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Video (now on Youtube!):&amp;lt;/p&amp;gt;
&amp;lt;iframe width="560" height="315" src="https://www.youtube.com/embed/C2Jum5neMJU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;

&amp;lt;p&amp;gt;I added Bits (the little blue things you can see in the video), which serve as a HP/time countdown hybrid. They decrease over time and you lose them by taking damage, representing your integrity as a little computer program guy, because, you know, that&amp;amp;rsquo;s exactly how that works (#1337hackz0r). I plan on making the games a little more swingy, by picking up Bits being a lot stronger, but also losing a lot more over time. Awesomely though they dont&amp;amp;rsquo;t just have an effect on a dandy little bar you can fill and empty, but also trigger a (placeholder) death screen, giving you the opportunity to start again.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Which leads me to the &amp;lt;a href="http://en.wikipedia.org/wiki/JMP_%28x86_instruction%29"&amp;gt;jmp&amp;lt;/a&amp;gt;-tiles, which don&amp;amp;rsquo;t just enable you to restart the game, but advance you to other maps once you cleared the room of all enemies, being a key part of the game and also finally implemented!&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Also the random weapons have been changed, so I don&amp;amp;rsquo;t have to restart the game ten times before I can make a video ;) Now they are a lot more even in power level (by equalizing metrics like damage per second), but I don&amp;amp;rsquo;t have the impression that they feel that diverse at the moment, which may change after I implemented a lot more special powers or I might just drop the random weapon idea alltogether and stick with weapon upgrades or something. Testing will tell! Also I integrated ShotSynth, which I mentioned (and showcased) in &amp;lt;a href="http://theshoemaker.de/2015/01/sudohack/"&amp;gt;a previous blog post&amp;lt;/a&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Some of you might have noticed (definitely those of you who had the gift of being asked to test the game) that the enemies are not as clever as they could be and often get randomly stuck or behave a little strange. I tweaked this a little and removed two huge bugs I&amp;amp;rsquo;m still ashamed to even think about, let alone mention to any living person. For days they collided with dead enemies, and significant parts of their behaviour were never executed (still did it).&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Formerly the movement was just a regular euler integration with friction and keypresses corresponded to forces that were being exerted on the player mass. But I think that it was really hard to dodge bullets and all in all the movement looked and felt very floaty, albeit smooth. I changed it to partly setting the velocity and partly interpolating into a target velocity, which should (and did) give the game a little more of a Gradius/R-Type feel regarding movement. I really like the change, though some have expressed dislike (In my opinion, mostly because of the significantly different feel).&amp;amp;nbsp; Also I invested a little time to make the game compatible with the 360 controller and added the traditional twinstick shooting controls, so you don&amp;amp;rsquo;t have to also press a button to shoot.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Finally the part that was definitely the most fun and the stuff that interests me the most in game programming: the graphics part. At first I added the grid effects, which can be explained if there is any need for it (just tell me), but certainly help to give the game it&amp;amp;rsquo;s cyber feel I was aiming for and also make the level a lot more dynamic and lively. To enhance these effects and because no cyber space game can live without copious amounts of it I added bloom/a glow effect, which still might be a little too much at the moment and will probably be toned done, but not until I got completely sick of it, which might take longer than anyone likes (but please tell me if you think that I should tackle my severe case of bloom addiction and kick it down a notch). Also I added a scanline and a rgb-shift shader, which should give the game the look of an old monitor, because again: cyber space and stuff. I plan on adjusting their parameters using the current amount of Bits, compromising the image more and more with less Bits being left. The bullets look a little prettier too, players have awesome, yet still unexplicable cyber-tails and on top of it all I managed to squeeze in approximately 60 hours of research and implementation for a neat little aim line.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I also tried a few level generators, that I really, really didn&amp;amp;rsquo;t like and at the moment I plan on not having random maps, but rather prebuilt and randomly chosen rooms. I will definitely put more time into a generator first, after I built a few to get a feel of what works and what doesn&amp;amp;rsquo;t.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The immediates milestones are a semi-working prototype for the &amp;lt;a href="http://globalgamejam.org/"&amp;gt;Global Game Jam&amp;lt;/a&amp;gt;, which I will attend from the 23rd to the 25th this month. For this the next things on my ToDo-list are a lot of minor changes, new enemies, a few maps and a new (wordpress) blog!&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>SudoHack - Enemies and Prettiness</title>
        
        <link href="https://joelschumacher.de/posts/sudohack-enemies-and-prettiness"/>
        <id>https://joelschumacher.de/posts/sudohack-enemies-and-prettiness</id>
        <updated>2015-01-07T00:09:00+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;SudoHack is a multiplayer roguelike where you and your friends, playing as computer programs, try to infiltrate a computer system. You gain &amp;amp;ldquo;Bits&amp;amp;rdquo; by destroying the guardian programs that are put in your way, but also lose them for every hit you take and every second that passes by. Your goal is to reach the end of the room before you run out of Bits and get destroyed yourself, therefore gaining access to deeper levels of the system, until you reach the core.&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I really should have spent the last few days on university stuff, but I really couldn&amp;amp;rsquo;t resist, I integrated two enemy types (a static turret and a &amp;amp;ldquo;moving turret&amp;amp;rdquo;, as it&amp;amp;rsquo;s called in the code) and a background for the &amp;amp;ldquo;floor&amp;amp;rdquo;, which was previously just black. Also the bullets look a little different now and being hit by enemy fire decreases your shared HP (&amp;amp;ldquo;Bits&amp;amp;rdquo;!) now, just as the general passage of time does. Looking at a diff from gitk tells me that I made a &amp;lt;u&amp;gt;&amp;lt;i&amp;gt;lot&amp;lt;/i&amp;gt;&amp;lt;/u&amp;gt; more changes, but most of them are not interesting or tangible enough (for non-programmers) to talk about. Also: screen shakes, flashes, explosions - the cool stuff. I think a video is the best I can do now, suspense curve-wise:&amp;lt;/p&amp;gt;
&amp;lt;iframe width="560" height="315" src="https://www.youtube.com/embed/Lb_SQ-z_g94" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;

&amp;lt;p&amp;gt;Here my roommate (thanks, Jonas!) and I tried a little round in one of the first (and highly unrefined) maps. The weapons are already randomly generated and trying them out or just trying to figure out the AI (which I programmed myself, but sadly still can&amp;amp;rsquo;t fully predict) is already quite fun.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;One of the biggest problems I encountered during this developement session is visual design in general. I had a really hard time figuring out proper palettes for the game and am still not really convinced by them. Also I&amp;amp;rsquo;m not sure if the current general art style of the game is what I have in mind for it. The general atmosphere is also still very much uncertain, but, I think, largely influenced by music and can easily be shaped with it. If anyone has good ideas regarding the design (colors, graphics, whatever it is), please let me know!&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;The AI also still has it&amp;amp;rsquo;s weaknesses (I think at the moment the AI is only a weakness) and it proved a lot harder than I thought to design proper state machines for convincing enemy behaviour. I also realized that this game is very, very dependant on proper balancing. Changing just a few values even a tiny bit has huge impacts on the enjoyability of the game and I think that it will take many, many hours to get it right. I&amp;amp;rsquo;m happy that it&amp;amp;rsquo;s still a while until I have to seriously tackle these problems, but it also makes me happy that a very fun game might just be a digit after the decimal place away! &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;The next steps I&amp;amp;rsquo;m going to tackle are various changes that, ideally should have no effect on the game dynamics themselves, but tidy up the code base a little and optimize some things that require it at the moment. After that I will change the way the game handles configuration files and make the first distributable version for the readers of this blog to enjoy! I hope that it will take me a few days (or a week), because that means that I spent my time on important stuff. Let&amp;amp;rsquo;s see how that goes..&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>SudoHack</title>
        
        <link href="https://joelschumacher.de/posts/sudohack"/>
        <id>https://joelschumacher.de/posts/sudohack</id>
        <updated>2015-01-05T01:05:00+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;During this holiday season I started to work on a &amp;amp;ldquo;new&amp;amp;rdquo; project. I actually started it quite a few times, but never really worked more than a few hours on it before I lost interest. But this time I don&amp;amp;rsquo;t just want to try a few things and code a small game, I want to know if I can finish one. Making a game from start to finish. With a menu and all (I never made menu). Also I often fantasized about about taking a year off after I got my Bachlor&amp;amp;rsquo;s degree (if it comes to that) and be an indie dev - this is how I want to find out if I could actually do it.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;SudoHack is going to be a a multiplayer roguelike, inspired by the numerous recent roguelikes, like The Binding of Isaac, Rogue Legacy, FTL: Faster than Light, which I played a lot of. It is set in cyber space and you (and your mates)  control little programs that try to infiltrate a system (which explains the name, if you ever used Linux, where the sudo command executes another command as the superuser). The key element is (and of course I&amp;amp;rsquo;m not sure if it will  actually end up that way) getting from room (which are prebuilt, but randomly chosen) to room without losing too many &amp;amp;ldquo;bits&amp;amp;rdquo;, which you will pick up as loot from your defeated enemies and also lose by taking damage. They are essentially a ticking timer and HP combined. The goal is to finish the room in time, get to another room and go from there, defeating bosses along the way and hopefully infiltrating the system completely at the end. So far I have a lot of boilerplate code, a mini collision library and shooting with bouncy bullets!&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;div style="clear: both; text-align: center;"&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style="clear: both; text-align: center;"&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style="clear: both; text-align: center;"&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style="clear: both; text-align: center;"&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style="clear: both; text-align: center;"&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style="clear: both; text-align: center;"&amp;gt;&amp;lt;object width="320" height="266" id="BLOG_video-35f59830c90472bb" class codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"&amp;gt;&amp;lt;param name="movie" value="//www.youtube.com/get_player"&amp;gt;&amp;lt;param name="bgcolor" value="#FFFFFF"&amp;gt;&amp;lt;param name="allowfullscreen" value="true"&amp;gt;&amp;lt;param name="flashvars" value="flvurl=http://redirector.googlevideo.com/videoplayback?id%3D35f59830c90472bb%26itag%3D5%26source%3Dblogger%26app%3Dblogger%26cmo%3Dsensitive_content%253Dyes%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1423912765%26sparams%3Did,itag,source,ip,ipbits,expire%26signature%3D3FDFDDBE58501BDEDA2DE4C9D74F73FB4ADED127.AA9C6B5C813403505562093BFC6062F9396BC236%26key%3Dck2&amp;amp;amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D35f59830c90472bb%26offsetms%3D5000%26itag%3Dw160%26sigh%3DclBYM312c03Swe4RQMq9882zRpg&amp;amp;amp;autoplay=0&amp;amp;amp;ps=blogger"&amp;gt;&amp;lt;embed src="//www.youtube.com/get_player" type="application/x-shockwave-flash" width="320" height="266" bgcolor="#FFFFFF" flashvars="flvurl=http://redirector.googlevideo.com/videoplayback?id%3D35f59830c90472bb%26itag%3D5%26source%3Dblogger%26app%3Dblogger%26cmo%3Dsensitive_content%253Dyes%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1423912765%26sparams%3Did,itag,source,ip,ipbits,expire%26signature%3D3FDFDDBE58501BDEDA2DE4C9D74F73FB4ADED127.AA9C6B5C813403505562093BFC6062F9396BC236%26key%3Dck2&amp;amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D35f59830c90472bb%26offsetms%3D5000%26itag%3Dw160%26sigh%3DclBYM312c03Swe4RQMq9882zRpg&amp;amp;autoplay=0&amp;amp;ps=blogger" allowFullScreen="true" /&amp;gt;&amp;lt;/object&amp;gt;&amp;lt;/div&amp;gt;&amp;amp;nbsp;Also, as you can see, local multiplayer is already implemented (the green guy is controlled using my controller and the red one using my keyboard and mouse). It is planned to also integrate networked multiplayer, but since I have never done this before (in contrast to everything else I have planned for this game) I&amp;amp;rsquo;m a little afraid of how it will turn out. I&amp;amp;rsquo;m confident that I can at least hack together &amp;lt;i&amp;gt;something&amp;lt;/i&amp;gt;, that probably works only on LAN, but I hope that I can do just a little bit more. Also this time I&amp;amp;rsquo;m using &amp;lt;a href="https://love2d.org/"&amp;gt;LÖVE&amp;lt;/a&amp;gt; again, which is, as usual, a pleasure. Next up are enemies, which I already designed a few of and really can&amp;amp;rsquo;t wait to integrate into the game. &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;One thing I already worked on way too much for a prototype is random weapons, which will be dropped as loot in the game. Every player starting the game will already have a randomly generated weapon (about 14 parameters). And for this feature in particular I started working on a shot sound synthesizer. Most of it&amp;amp;rsquo;s features can be seen in the description text in the video below. Obviously it also contains a few sounds I generated just pressing the space key a few times.&amp;lt;br /&amp;gt;&amp;lt;div style="clear: both; text-align: center;"&amp;gt;&amp;lt;object width="320" height="266" id="BLOG_video-3d1b73b9e269d9fa" class codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"&amp;gt;&amp;lt;param name="movie" value="//www.youtube.com/get_player"&amp;gt;&amp;lt;param name="bgcolor" value="#FFFFFF"&amp;gt;&amp;lt;param name="allowfullscreen" value="true"&amp;gt;&amp;lt;param name="flashvars" value="flvurl=http://redirector.googlevideo.com/videoplayback?id%3D3d1b73b9e269d9fa%26itag%3D5%26source%3Dblogger%26app%3Dblogger%26cmo%3Dsensitive_content%253Dyes%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1423912765%26sparams%3Did,itag,source,ip,ipbits,expire%26signature%3D5746C07FE79D3C59650A53D3F51FBF00DDF5D1FA.A0D67504075F27A400C97C8708CFB297375F506A%26key%3Dck2&amp;amp;amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D3d1b73b9e269d9fa%26offsetms%3D5000%26itag%3Dw160%26sigh%3DeI2XHNWHlgfaduoZ14yLn5fD7IU&amp;amp;amp;autoplay=0&amp;amp;amp;ps=blogger"&amp;gt;&amp;lt;embed src="//www.youtube.com/get_player" type="application/x-shockwave-flash" width="320" height="266" bgcolor="#FFFFFF" flashvars="flvurl=http://redirector.googlevideo.com/videoplayback?id%3D3d1b73b9e269d9fa%26itag%3D5%26source%3Dblogger%26app%3Dblogger%26cmo%3Dsensitive_content%253Dyes%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1423912765%26sparams%3Did,itag,source,ip,ipbits,expire%26signature%3D5746C07FE79D3C59650A53D3F51FBF00DDF5D1FA.A0D67504075F27A400C97C8708CFB297375F506A%26key%3Dck2&amp;amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D3d1b73b9e269d9fa%26offsetms%3D5000%26itag%3Dw160%26sigh%3DeI2XHNWHlgfaduoZ14yLn5fD7IU&amp;amp;autoplay=0&amp;amp;ps=blogger" allowFullScreen="true" /&amp;gt;&amp;lt;/object&amp;gt;&amp;lt;/div&amp;gt;&amp;amp;nbsp; &amp;lt;br /&amp;gt;Both SudoHack and the ShotSynth in their current versions are available on GitHub:&amp;lt;br /&amp;gt;&amp;lt;a href="https://github.com/pfirsich/ShotSynth"&amp;gt;https://github.com/pfirsich/ShotSynth&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;a href="https://github.com/pfirsich/SudoHack"&amp;gt;https://github.com/pfirsich/SudoHack&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;If anyone in the world ever reads this (highly improbable) and doesn&amp;amp;rsquo;t know how to get this game to run on his computer using the GitHub repository I linked here, but really wants to try, comment this blog post and I&amp;amp;rsquo;ll upload a binary :)&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>The Delightful Reunification With Modify-Assign in Lua and Per Torpedum ad Astram</title>
        
        <link href="https://joelschumacher.de/posts/modify-assign-in-lua-per-torpedum-ad-astram"/>
        <id>https://joelschumacher.de/posts/modify-assign-in-lua-per-torpedum-ad-astram</id>
        <updated>2014-12-30T12:42:00+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;Jonas, who already worked on Spacewalk with me, and another fellow student of mine recently became roommates after Jonas and third said roommate spent a year abroad. Jonas and I decided to visit the Global Game Jam in Cologne in January and felt it was necessary to do some kind of warm up to get comfortable with the technology we plan on using and produce some useful code for loading &amp;lt;a href="http://www.mapeditor.org/"&amp;gt;Tiled&amp;lt;/a&amp;gt; (which just keeps getting better and better, geez!) maps and general boilerplate. After a while I again noticed the painful lack of &amp;lt;code&amp;gt;+=&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;-=&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;*=&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;/=&amp;lt;/code&amp;gt; operators in Lua. I remembered writing a Python script (which is bad) that compiled &amp;amp;ldquo;.mond&amp;amp;rdquo; to Lua only adding said assignment operators in functionality and significant whitespaces instead of those ugly &amp;lt;code&amp;gt;then&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;do&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; blocks. I now know though, that it is possible to add loaders to Lua that will be invoked once a module will be &amp;amp;ldquo;require&amp;amp;rdquo;d in a source file. So I wrote a loader that gives me those missing operators (replaces them before passing the source to loadstring)! The loader and an example of this using löve2D can be found here:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="https://github.com/pfirsich/ModifyAssignInLua"&amp;gt;https://github.com/pfirsich/ModifyAssignInLua&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;If I or you (if anyone would ever read this) would like to use it, you just have to rename your actual &amp;lt;code&amp;gt;main.lua&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;realmain.lua&amp;lt;/code&amp;gt; (or however you want to name it. But don&amp;amp;rsquo;t forget to change the name in &amp;lt;code&amp;gt;main.lua&amp;lt;/code&amp;gt;!) and include &amp;lt;code&amp;gt;mond.lua&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;main.lua&amp;lt;/code&amp;gt; in your project folder (without löve the usage is very similar to this).&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;As you can see in &amp;lt;code&amp;gt;mond.lua&amp;lt;/code&amp;gt;, line 33 ff. I also kept the option to parse completely different source files and do something like I did in the Python version of Mond (replacing the Lua blocks with significant whitespaces (actually the other way round of course)), but I think that this is, though nice and fun, a little of a waste of time, since I should actually be working important things.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The last 5 posts were part of the TAG Jam, which I got to host, since I won TAG Jam 5: &amp;lt;a href="http://blog.ratalaika.com/tag/tagjam/"&amp;gt;http://blog.ratalaika.com/tag/tagjam/&amp;lt;/a&amp;gt; (here you can find my game too of course! &amp;lt;strong&amp;gt;Read the readme&amp;lt;/strong&amp;gt;!) (&amp;lt;strong&amp;gt;&amp;lt;span style="text-decoration: underline;"&amp;gt;Update 7th of April 2015&amp;lt;/span&amp;gt;&amp;lt;/strong&amp;gt;: This link seems to be broken. You can &amp;lt;a href="https://www.dropbox.com/s/gvb3vomavw5lrxu/PerTorpedumAdAstram.zip?dl=0"&amp;gt;download it from my Dropbox&amp;lt;/a&amp;gt; instead. Or &amp;lt;a href="https://www.youtube.com/watch?v=723aAV4LAd8"&amp;gt;watch a video of it on Youtube&amp;lt;/a&amp;gt;). I think the version that can be downloaded on Ratalaika&amp;amp;rsquo;s blog is not the most recent one and not the one with all known bugs fixed and all typos corrected, but this game is already almost one year old, so I don&amp;amp;rsquo;t really know what is what.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Screenshot for completeness&amp;amp;rsquo; sake:
&amp;lt;a href="/images/per_torpedum_ad_astram.png"&amp;gt;&amp;lt;img alt="Per Torpedum Ad Astram" src="/images/per_torpedum_ad_astram.png" /&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;This time, as stated in the readme, I worked on the game with a lot less pressure. I didn&amp;amp;rsquo;t want it to be good. I did it myself and I just wanted to spend a little time programming a game that I think would be cool. I purposely kept the scope of the game as small as I could imagine and this time it was just right for 48 hours. Apparently I still have problems keeping the scope small enough and not trying to do too much. This was easily the most fun game jam yet. Also the game being a game emulating the Starfox gameplay helped a lot, since it is one of my favourite franchises and one I have the fondest memories of. I&amp;amp;rsquo;m also a little proud of the unique graphics style. By that I don&amp;amp;rsquo;t just mean the exceptionally sub-par artwork, but the pseudo 3D visuals and the clouds and the graphics feel in general.&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>TAG Jam #6 - Results</title>
        
        <link href="https://joelschumacher.de/posts/tag-jam-6-results"/>
        <id>https://joelschumacher.de/posts/tag-jam-6-results</id>
        <updated>2014-01-08T00:01:00+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;Hi guys! I found some time and decided to playtest/write a resumé.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;First of all I found it really interesting that there are not that many multiplayer games (just one) and that one also tried to make a game without an objective. I&amp;amp;rsquo;m really happy that all of you tried to make something different :)&amp;lt;/p&amp;gt;
&amp;lt;h3 id="clouds"&amp;gt;Clouds&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;This is exactly what I meant! Games like this. I think this one fits what I had in mind best. Many exploration games (like they were made here and playground-games) kind of have an objective in a sense that you want to do something. This one though is a game where you are finished the second you start playing, but you choose to keep on going. Like a scenery or a photograph, but dynamic and interactive. The music (which is really good by the way!) changes are a little abruptly and is disrupting the mood in my opinion, which is super important to avoid in a game like yours. All in all it&amp;amp;rsquo;s, sadly, just not very much and even if you decide to keep on playing, it loses it&amp;amp;rsquo;s appeal fairly soon.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Technically: Maybe you could have spent some time investigating how to visualize rain nicely. Even rain drops with different speeds would have been a little more realistic. So it would have if you paid more attention on the tiling of the rain texture. I also don&amp;amp;rsquo;t like that the rain clouds get repelled and move away with constant speed. Maybe only repulsion would&amp;amp;rsquo;ve looked nicer - not entirely sure.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="you-only-need-one"&amp;gt;You Only Need One&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;First of all the title really reminds me of the last Ludum Dare theme (You Only Get One). At first I was a little confused since no one told me how to control the game! This is something that you should pay attention to. After figuring out to use the arrow keys though I must say that I really liked the setting and it really awakened my interest. The pacing of finding out what&amp;amp;rsquo;s happening in the beginning is really good in my opinion! I like using the word &amp;amp;ldquo;odd&amp;amp;rdquo; as an inspiration and am generally delighted by the setting. It&amp;amp;rsquo;s continually more interesting! I don&amp;amp;rsquo;t like though that the game actually has an objective. You want to get to the end, because you know there is one. It&amp;amp;rsquo;s just not explicitly stated. The suspense curve really takes it&amp;amp;rsquo;s time to bottom out. The last part is not very rewarding considering the growing platforming-difficulty.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Technically: I&amp;amp;rsquo;m not sure how easy it is to do this in flash, but I would have liked it if the speech bubbles faded out. Also the music loops very strangely and starts again when you just forgot about it. Constantly playing music would have improved the experience, I guess.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="go-figure"&amp;gt;Go Figure&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;I really like the name! It&amp;amp;rsquo;s a nice thing to play around, but loses it&amp;amp;rsquo;s appeal rather quickly. It&amp;amp;rsquo;s more of a toy than a real &amp;amp;ldquo;game&amp;amp;rdquo;. I don&amp;amp;rsquo;t want to be mean, but just because a game doesn&amp;amp;rsquo;t have a game, it should still be enjoyable! That was part of the challenge. Something where it&amp;amp;rsquo;s all about the experience and the mood. At least that&amp;amp;rsquo;s what I had in mind and because it&amp;amp;rsquo;s just me, I should probably not criticize your game for it!&amp;lt;/p&amp;gt;
&amp;lt;h3 id="revel"&amp;gt;Revel&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;I really like the mood and the music and the graphics! Atmosphere-wise you did a really, really good job. The location is intriguing and the character as well (4 arms, when I first jumped! Very cool moment). Execution-wise this is probably the best game (it has to be mentioned though that you are a significant amount of people) and fits the Outsider theme very well. I really like that the game doesn&amp;amp;rsquo;t stop to give you something to explore. What I don&amp;amp;rsquo;t like is that it eventually does and not in a very elegant fashion. I probably just got stuck, because I didn&amp;amp;rsquo;t know that to do, but that&amp;amp;rsquo;s not just my fault. I collected the two artifacts (which I think is a little silly of you to write directly on them :D) and found the little cave below the starting room which you can&amp;amp;rsquo;t see much in. I&amp;amp;rsquo;m actually pretty sure I&amp;amp;rsquo;m stuck, but I don&amp;amp;rsquo;t know that to do. So I&amp;amp;rsquo;m not really sure if it&amp;amp;rsquo;s really without an objective, since having a goal and being able to finish still kind of qualifies as one. Also I think the game would have benefited a lot from parallax effects in the background!&amp;lt;/p&amp;gt;
&amp;lt;h3 id="uphero"&amp;gt;Uphero&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;(At least I hope that it&amp;amp;rsquo;s called that way). The first 4 times I started the game the player apprently spawned in the level geometry, which really confused me and made me restart the game until it did not. After I&amp;amp;rsquo;ve seen him and played the game I of course realized that I could set him free by deleting the blocks. And when I saw him I was happy to find such a cute little guy. He&amp;amp;rsquo;s awesome. And the music is too. It&amp;amp;rsquo;s not less groovy than you said (which is uber). I generally don&amp;amp;rsquo;t like that you just took an already existing game and tried to clone it. In general this is not a bad thing, and it doesn&amp;amp;rsquo;t make the game worse, but is a minus point when it comes to winning (which is probably understandable). The sun and the clouds look just a nice as the alien, but I don&amp;amp;rsquo;t really like that it&amp;amp;rsquo;s so easy to place blocks. I think that Minecraft and Terraria make building things rewarding, because it&amp;amp;rsquo;s work. It&amp;amp;rsquo;s just too easy to do something. Also I struggle with rather low FPS once I move. When moving the FPS really fluctuate quite a bit, which is really disruptive.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;PS: Sorry for pointing out the positive stuff at the beginning and the negative stuff at the end. I don&amp;amp;rsquo;t want to rewrite it, but don&amp;amp;rsquo;t think that I disliked any single one of your games! All of them were a pleasure to play! I&amp;amp;rsquo;m really happy that five people took their time on a weekend to participate in a game jam I had the pleasure to host! Thank you all for participating! I hope you had a lot of fun and learned equally as much!&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;h3 id="to-cut-to-the-chase-the-winner-is-revel"&amp;gt;To cut to the chase, the winner is: &amp;lt;strong&amp;gt;Revel!&amp;lt;/strong&amp;gt;&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;After playing all your games I didn&amp;amp;rsquo;t find it easy to decide which is the best, but I think that it&amp;amp;rsquo;s actually just the one which yielded the most enjoyable experience during the time playing (even though there a some things to criticize, as with all the games), which was your team&amp;amp;rsquo;s, Charles! Congratulations!&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>TAG Jam #6 - Time&#39;s Up!</title>
        
        <link href="https://joelschumacher.de/posts/tag-jam-6-times-up"/>
        <id>https://joelschumacher.de/posts/tag-jam-6-times-up</id>
        <updated>2014-01-06T00:00:00+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;The jam time has ended! I hope you had a lot of fun during the last 48h+! Please upload your games now and link to them in the comments below. You will then have 12 hours to fix bugs and package everything. The final deadline for uploading your games is Monday 12:00 GMT/Monday 04:00 PST. I try to write up a little review for all the games and determine a winner by the end of the week. I sadly didn&amp;amp;rsquo;t finish my game (not even remotely) due to a rather busy weekend, but I am super excited about what you came up with :)&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>TAG Jam #6 - The Jam Time Begins!</title>
        
        <link href="https://joelschumacher.de/posts/tag-jam-6-the-jam-time-begins"/>
        <id>https://joelschumacher.de/posts/tag-jam-6-the-jam-time-begins</id>
        <updated>2014-01-04T00:00:00+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;And the second, even more special, moment has finally come too. The jam time begins!&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;a href="http://theshoemaker.de/2014/01/tag-jam-6-themes/"&amp;gt;- The Themes - &amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;a href="http://theshoemaker.de/2013/12/tag-jam-6-welcome-post/"&amp;gt;- The Rules -&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;The deadline is now in 48 hours, respectively Sunday 24:00 GMT/Monday 00:00 GMT/Sunday 16:00 PST. Then you will have 12 hours submission time. Feel free to add the 12 hours yourself and not make me write down all the different times in all the different time zones again. Your submissions can be linked to under another post I will create when the jam time ends. &amp;lt;br /&amp;gt;Have fun! :)&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>TAG Jam #6 - Themes</title>
        
        <link href="https://joelschumacher.de/posts/tag-jam-6-themes"/>
        <id>https://joelschumacher.de/posts/tag-jam-6-themes</id>
        <updated>2014-01-03T00:00:00+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;Okay! The special moment has come; the magic begins. No screwing around - the themes:&amp;lt;br /&amp;gt;&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Outsider - &amp;lt;i&amp;gt;&amp;amp;ldquo;a person who does not belong to a particular organization or profession&amp;amp;rdquo; / &amp;amp;ldquo;a competitor, applicant, etc. thought to have little chance of success&amp;amp;rdquo;&amp;lt;/i&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;Drawback - &amp;lt;i&amp;gt;&amp;amp;ldquo;a feature that renders something less acceptable; a disadvantage or problem&amp;amp;rdquo; &amp;lt;/i&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;Affection - &amp;lt;i&amp;gt;&amp;amp;ldquo;a gentle feeling of fondness or liking&amp;amp;rdquo;&amp;lt;/i&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;(Definitions from oxforddictionaries.com)&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;There they are. All (semi-)randomly (I picked them from a larger pool of words) generated by &amp;lt;a href="http://www.wordgenerator.net/random-word-generator.php"&amp;gt;http://www.wordgenerator.net/random-word-generator.php&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;Your game has to do with one or more of these themes. The jam time will officially start in 24 hours which is Friday 24:00 GMT/Saturday 00:00 GMT/Friday 16:00 PST/4pm PST (now I hope that everybody knows when it is) and will last for 48 hours.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;Don&amp;amp;rsquo;t forget the special rules for TAG Jams half-birthday! - &amp;lt;a href="http://theshoemaker.de/2013/12/tag-jam-6-welcome-post/"&amp;gt;Look here!&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>TAG Jam #6 - Welcome Post</title>
        
        <link href="https://joelschumacher.de/posts/tag-jam-6-welcome-post"/>
        <id>https://joelschumacher.de/posts/tag-jam-6-welcome-post</id>
        <updated>2013-12-23T16:26:00+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;Hi everyone!&amp;lt;br /&amp;gt;Sorry for the delay, but here&amp;amp;rsquo;s the countdown/welcome-post for #TAGJam6! I won&amp;amp;rsquo;t be using twitter, but for all you interested in doing so, the aforementioned one is the hashtag to use. Ticktakashi pointed out that with this one TAG is celebrating it&amp;amp;rsquo;s half-birthday (which totally is a thing)! Therefore we will have special rules and since I&amp;amp;rsquo;m not really big on decision making, we will just include a set of two additional rules from which you will have to choose one (or more, which is two and also all of them).&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;These rules are as follows:&amp;lt;br /&amp;gt;&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Create a multiplayer game (local multiplayer is of course fine too and probably the way to go with such time constraints)&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;Create a game without an objective (and (extra sugar) without enemies)! Whether it may be explorative in nature or just some kind of interactive experience or even something else. Make something different!&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;The themes (2 random ones and one of my choice) will be announced on Thursday January 2nd 24:00 GMT/16:00 PST and the game jam will start 24 hours later on Friday 3rd at 24:00 GMT/16:00 PST (e.g. Saturday 00:00 GMT), so you have 24 hours to ponder on the themes.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Feel free to comment this blog entry, so I know who of all you awesome people I can expect to participate!&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The full rules are here: &amp;lt;a href="http://www.thearbitrarygamejam.com/"&amp;gt;http://www.thearbitrarygamejam.com/&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Edit: I did a mistake on the dates. I changed my Windows-calendar to January without changing the year -.-&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>Metroidlike &amp; 2D-Water &amp; Bone-Animations - Catching Up Part 1</title>
        
        <link href="https://joelschumacher.de/posts/metroidlike-2d-water-bone-animations"/>
        <id>https://joelschumacher.de/posts/metroidlike-2d-water-bone-animations</id>
        <updated>2013-12-20T16:58:00+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;I have a huge list of stuff that I should have put on my blog (just to document what I&amp;amp;rsquo;m programming and maybe have a look at the progression afterwards) and today is the day I try to catch up. I&amp;amp;rsquo;m thinking about making big posts with multiple things I worked on, so I don&amp;amp;rsquo;t have to create a myriad of posts today and also because some of them are related. Especially the three in this post, since they were intended to be part of the same game.&amp;lt;/p&amp;gt;
&amp;lt;h2&amp;gt;Metroidlike&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;I love the Metroid franchise. Almost every metroid game is one of my favourite games ever (except the Wii-Titles since I haven&amp;amp;rsquo;t played them). And for anyone wondering which I think are the best: My number one is Super Metroid without a doubt. I adore this game indefinitely. Prime and Fusion in no particular order are also among the better ones. So all along my time of programming games I started many Metroid 2D or Metroid Prime clones (though I never finished one) and I felt that it is again time to make one, since I know a whole lot more and had nothing to to do and a huge urge to start a project.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Although I&amp;amp;rsquo;m doing mostly 2D-stuff lately I&amp;amp;rsquo;m a really graphics-affine guy and I really like to spend time making effects and I&amp;amp;rsquo;m really interested in graphics techniques, so naturally I spent most of my efforts on making the game look nice. First a video:
&amp;lt;center&amp;gt;&amp;lt;iframe width="560" height="315" src="https://www.youtube.com/embed/dJSdzbMAj7Y" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;/center&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;As you will see again I tried to make the content-creation-pipeline for this game really programmer-friendly, so part of the look has to do with that. I know that tiles are a really easy way to make level geometry, but I think that they often just look a little jaggy and not as next-gen as they could, so I decided to make &amp;amp;ldquo;high resolution tiles&amp;amp;rdquo;, which are tilesets with very many different tiles. I wrote a program that generates such tile maps for me, passing the resolution of the resulting tile map and the number of points per side. Here is an example of the map used for this level and with 5 points per side:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;img alt="" src="/images/metroidvania_tilemap.png" /&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;This makes it possible to make level geometry which can have very irregular shapes as you can see in the video (but only at the beginning of the level since I got a little lazy after that). These mono-coloured tile maps are then masked in a shader with a texture. In this case I used a rock texture. In the main program the tile map is rendered black on a white backdrop which as a whole is then blurred. This image is then used as a light-map. Also there are raytraces done from the top side of the map to genereate shadows and a sense of &amp;amp;ldquo;inside and outside&amp;amp;rdquo; (regarding inside the cave and outside the cave). Also the gradient in the background is generated that way. I also used a form of deferred rendering, but in multiple passes since löve doesn&amp;amp;rsquo;t support multiple render targets and multi-texturing. The normal maps and an image consisting of the lights (in the video: player and bullets) are rendered seperately and the resulting lighting is calculated in a final composition-pass. Especially the specular reflections make it look very plastic. I must say, that I really like the look of the game.&amp;lt;/p&amp;gt;
&amp;lt;h2&amp;gt;2D-Water&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;I intended the game to start deep down in a cave, probably with the main character being unconscious lying in a little puddle or a little mini-lake. So I got started with programming water! First the video:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;center&amp;gt;&amp;lt;iframe width="560" height="315" src="https://www.youtube.com/embed/6onBYjnob7w" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;/center&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Excuse the waves, which seem to be splashing way to high. This has to do with the fact that I didn&amp;amp;rsquo;t implement fixed timesteps in this test program and Fraps having a huge impact on framerate, making the forces way more impactful than at a high framerate.
Just a little while ago a new löve-version was released which allows user defined geometry with user defined texture coordinates (but I don&amp;amp;rsquo;t know how much control is given over the way the geometry is stored. Since we want to update it every frame, one needs the possibility to make the VBO of type &amp;lt;code&amp;gt;GL_STREAM_DRAW&amp;lt;/code&amp;gt;, but at the time I did this I had to find another way, which then consisted of an array of values, which represent the height of the water surface. In the water-shader these values are interpolated for every x and the water surface is drawn accordingly. The actual geometry drawn is a box that encloses the water and it&amp;amp;rsquo;s waves. This also makes it rather easy to not only make a sharp border, but also give the color a gradient (which I did) and highlight the surface, which improves the realism &amp;lt;b&amp;gt;a lot&amp;lt;/b&amp;gt;. Water getting darker when it&amp;amp;rsquo;s deeper is one of the things that a lot of water-implementation that don&amp;amp;rsquo;t seem right lack. Also there is obviously a distortion-texture and the previously rendered scene passed to the shader (so this has do be done in a separate pass) to achieve the distortion effect, which also has a huge impact it looking plausible and is also not hard to implement. The values passed to the shader are determined in the main program using collision-checks of points on the water surface with the game world&amp;amp;rsquo;s geometry. The forces acting on the points are consisting of a force that always puts the point to the zero-level of the water surface (a harmonic force), damping (linear) and a relative harmonic force between the points to couple the oscillators so waves can pass through them. To make the simulation more stable I&amp;amp;rsquo;m using a form of verlet integration and multiple iterations per frame. Also there is a force which is responsible for the box to be able to &amp;amp;ldquo;push&amp;amp;rdquo; water, that is calculated by checking the velocity of every object that collided with the surface and pushing the water up in front of the moving object and pushing it down behind it (in front and behind are obviously determined by the velocity) This water effect alone makes mit a little sad that I decided to stop working on this project.. But there is even more cool stuff, like:&amp;lt;/p&amp;gt;
&amp;lt;h2&amp;gt;Bone-Animations&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;As I said before, I wanted to make the pipeline very programmer-friendly. And since drawing is probably my worst skill I just &amp;lt;span style="text-decoration: underline;"&amp;gt;had&amp;lt;/span&amp;gt; to have bone animations. It is also something that I wanted on multiple occasions for a very long time. And after searching the net for a freeware 2D bone animations editor with an easy to read format and not finding anything, I decided to roll my own.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;This is also just semi-finished and not very sophisticated feature-wise. The only thing missing is a proper way to specify interpolation curves for the frames. There is not an easy way to approach this by using only one type of interpolation (linear, smoothed) because different things need very different types of interpolation. So there is an editor missing for that kind of stuff and this is actually the point where I started to stop the project for other stuff I&amp;amp;rsquo;m busy with. Writing this though made me really want to keep on working on it. I have a feeling that a well-working animation editor might not just be something nice I can find use of a few times, but something other people might find useful too. There are some things that make it not very useful for other people though, which is mainly löves policy of not making it possible to write to the file system outside of &amp;lt;code&amp;gt;C:\Users\user\AppData\Roaming\LOVE&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;%appdata%\LOVE&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Maybe I should start a rewrite in C++ or Python or similar and this is certainly too much work to be still interested in continuing.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="pictures-video"&amp;gt;Pictures / Video:&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;RiggEd, which is for rigging (making bone skeletons and attaching images):&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;img alt="" src="/images/rigged_guy_1.png" /&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;img alt="" src="/images/rigged_guy_2.png" /&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;img alt="" src="/images/rigged_plant_1.png" /&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;img alt="" src="/images/rigged_plant_2.png" /&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;AnimEd (has two files to deal with. A &amp;lt;code&amp;gt;.skel&amp;lt;/code&amp;gt;-file which is the output of RiggEd and contains a skeleton with images and an &amp;lt;code&amp;gt;.anim&amp;lt;/code&amp;gt; files which contains keyframes for the skeleton. The &amp;lt;code&amp;gt;.anim&amp;lt;/code&amp;gt; files can be used on multiple skeletons, so the animations can be reused for different characters and different image sets:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;img alt="" src="/images/animed_1.png" /&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;img alt="" src="/images/animed_2.png" /&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;img alt="" src="/images/animed_3.png" /&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;img alt="" src="/images/animed_4.png" /&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;img alt="" src="/images/animed_5.png" /&amp;gt;&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>BaconGameJam5 &amp; löve</title>
        
        <link href="https://joelschumacher.de/posts/bacongamejam5-love"/>
        <id>https://joelschumacher.de/posts/bacongamejam5-love</id>
        <updated>2013-07-03T12:30:00+0000</updated>
        <content type="html">&amp;lt;h3 id="love"&amp;gt;löve&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;About a month ago I participated in the fifth BaconGameJam, which is a game jam that started as &amp;amp;ldquo;RedditGameJam&amp;amp;rdquo;, but had to be renamed due to copyright issues, so it&amp;amp;rsquo;s the former actually unofficial official reddit game jam and now more of a official unofficial reddit game jam. To get to the point I have to mention that I wasn&amp;amp;rsquo;t really sure what technology to use, because using Kiwi is way too stressfull since C++ is not a very productive language for very short amounts of developement time (My opinion at least.), so Pywi (the Python version of Kiwi) was actually my weapon of choice just before the jam started, but I knew that Pywi still had a few problems with sound and that I was not very keen of distributing a 48h-game with a rather huge Python interpreter + Pymedia, Pygame, numpy (we used this in collision detection and a few other parts), so I spontaneously decided to use &amp;lt;a href="https://www.love2d.org/"&amp;gt;löve&amp;lt;/a&amp;gt;, which is 2D game engine, which is implemented in C++, but used in embedded &amp;lt;a href="http://www.lua.org/"&amp;gt;Lua&amp;lt;/a&amp;gt;. And I must say, that löve is probably the most &amp;lt;em&amp;gt;awesome&amp;lt;/em&amp;gt; framework I&amp;amp;rsquo;ve ever used. I already tried using some other engines rather than my own, but every time I had the impression that there was something about them that bugged me so much, that I didn&amp;amp;rsquo;t really want to start any kind of project with them, but löve is almost exactly like I would like a game engine to be (API-wise). After using it for a while I noticed quite a few things that were not entirely to my liking, but most of these things are going to be changed in the next major release 0.9.0 and the rest is either not very important or something I could fix myself, since löve is open source. One of these more important things I decided to tackel myself was the integration of some proper games-oriented network library (in my case: &amp;lt;a href="http://enet.bespin.org/"&amp;gt;ENet&amp;lt;/a&amp;gt;). Thankfully a bunch of people already made some significant progress towards integration ENet into löve, namely leafo with &amp;lt;a href="http://leafo.net/lua-enet/"&amp;gt;lua-enet&amp;lt;/a&amp;gt; and Martin Felis with &amp;lt;a href="https://bitbucket.org/MartinFelis/love-enet"&amp;gt;love-enet&amp;lt;/a&amp;gt;, which my integration &amp;lt;a href="https://bitbucket.org/schmirsich/love-enet-new/overview"&amp;gt;love-enet-new&amp;lt;/a&amp;gt; is &amp;lt;i&amp;gt;largely &amp;lt;/i&amp;gt;based. The differences are mostly things regarding the &amp;amp;ldquo;how&amp;amp;rdquo; rather than the &amp;amp;ldquo;what&amp;amp;rdquo;. The API is more &amp;amp;ldquo;lövely&amp;amp;rdquo; (commonly used as &amp;amp;ldquo;fitting with the löve-API stylewise) and the integration of the added enet-module is mostly just like and other löve module is integrated in the engine. A working version of this was proposed about two weeks ago in the issue tracker (&amp;lt;a href="https://bitbucket.org/rude/love/issue/645/enet-integration-take-two"&amp;gt;link&amp;lt;/a&amp;gt;), but was yet not responded to, which is kind of a bummer, but I hope that this will workout somehow and someday ENet will be available in löve officially.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="bacongamejam"&amp;gt;BaconGameJam&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;Of course there is still game to talk about (BaconGameJam), which was nameless until the very end. This story is equally unimpressive since again, but this time even worse, I didn&amp;amp;rsquo;t really finish in time. I wasn&amp;amp;rsquo;t really enthusiastic about the theme or my idea from the beginning and actually only chose the idea from my list of ideas because there wasn&amp;amp;rsquo;t anything else I even remotely wanted to do.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(By the way: The theme was &amp;amp;ldquo;Lights Out&amp;amp;rdquo; and I decided to make a game in which you would wake up and walk around town discovering dead people and devastation, collecting clues and talking to people uncovering that the guy you play actually became a monster last night (when the lights went out), which is then replayed as kind of a &amp;amp;ldquo;reconstructed memory&amp;amp;rdquo; backwards &amp;amp;ldquo;creating&amp;amp;rdquo; the clues you collected and ending at the point the game started as a human, but as a monster.)&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;I don&amp;amp;rsquo;t intend to show you what I managed to finish, but rather summarize what I learned about participating in a game jam. I don&amp;amp;rsquo;t have very much to be proud of then, but I have learned a lot more, which does not feel as good, but is way more valuable.&amp;lt;br /&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;It&amp;amp;rsquo;s not a good idea to make a game with a strong emphasis on story, because.. 48 hours. How am I am I supposed to make a game and invest at least twice as much time in content (levels, dialogues). Instead I should make games which center around a core mechanic or are very easy to make content for.&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;I&amp;amp;rsquo;m alone and a programming guy, so I should make games that can be done by a programming guy alone. Needing tile sheets, character sprites etc., which I am not capable of making in a game is just not a good requirement to start with and bound to not work out very well. I should stick to simple sprites, stylised graphics, which are easy to make or boxes/circles/lines.&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;Probably the most important: Accepting defeat. If I don&amp;amp;rsquo;t have a good idea or it&amp;amp;rsquo;s probably not very realistic to transform the ideas I have into a enjoyable game in 48 hours I should probably not even start and waste a weekend, feeling bad afterwards. Maybe I should even deign to make the most obvious and easy game to a theme I can think of because in the end I would have an obvious game that no one is exceptionally ecstatic about, which is not so great, rather than having no game, which no one will be at least a bit ecstatic about, which is not even great at all.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;Yep. That&amp;amp;rsquo;s it. The next Ludum Dare is next month (actually just a little less than two months), so I will see how much these lessons actually taught me.&amp;amp;nbsp;&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>Spacewalk - Part 1</title>
        
        <link href="https://joelschumacher.de/posts/spacewalk-part-1"/>
        <id>https://joelschumacher.de/posts/spacewalk-part-1</id>
        <updated>2013-04-07T19:02:00+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;During my practical course in experimental physics I decided not to use C++ this time, but rather a language which has a way more extensive standard library and is way easier to debug. Just a language.. that is easier, in a sense. Long story short: I chose &amp;lt;a href="http://python.org/"&amp;gt;Python&amp;lt;/a&amp;gt; and fell in love. I then decided in a few free days to write up a little engine which is very similar to Kiwi (my C++ engine) now called Pywi. A buddy of mine and me then decided to put this engine to test, so we can maybe use it for the upcoming &amp;lt;a href="http://www.ludumdare.com/"&amp;gt;Ludum Dare&amp;lt;/a&amp;gt;. At first we struggled a bit with finding an idea we both would like to implement, but after looking at one of my idea-lists, we decided to 2D-ify one, named &amp;amp;ldquo;Spacewalk&amp;amp;rdquo;. It essentially explores multiplayer deathmath and capture the flag in space, but with level geometry consisting of materials with a very high mass. We actually had a few videos which were a little more impressive and capturing the mind-bending-fast-paced-style we would like to achieve in the end more appropriately (just more appropriately but in fact not at all), but somehow Fraps broke these files and neither WMP, nor VLC and MPlayer could play them back. We made these videos almost one and a half weeks ago and were not able to work on this game together since, so it&amp;amp;rsquo;s just this!
&amp;lt;center&amp;gt;&amp;lt;iframe width="560" height="315" src="https://www.youtube.com/embed/_4EkPm3LLYg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;/center&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;h3 id="polygons-and-gravity"&amp;gt;Polygons and Gravity&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;Technically we first weren&amp;amp;rsquo;t sure if the level should consist of predefined elements, a huge image that&amp;amp;rsquo;s used as a gravity-source or something polygony-vectory. Inspired by &amp;lt;a href="http://soldat.pl"&amp;gt;Soldat&amp;lt;/a&amp;gt; we decided to use polygons. We used Inkscape to draw these curves and export them to svg, which is then parsed, triangulated and rasterized. The rastered image will be interpreted as a cloud of point masses (every pixel drawn) and the resulting gravitational potential is stored in an numpy-array and saved (an image essentially). In-game we take the numerical pseudo-gradient &amp;lt;code&amp;gt;grad V = (dV/dx, dV/dy) with dV/dx = (V(x + h) - V(x - h)) / 2h&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;h&amp;lt;/code&amp;gt; being one pixel and use this as the gravitational force. Also we calculate &amp;lt;code&amp;gt;1/(r + r_0)&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;1/r&amp;lt;/code&amp;gt; to make the potential less steep, so we can choose a fairly high gravitational constant (because &amp;lt;code&amp;gt;1/r^2&amp;lt;/code&amp;gt; decays quite fast) without the player sticking to the level geometry too hard.&amp;lt;/p&amp;gt;
&amp;lt;h3 id="net"&amp;gt;Net&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;This was &amp;lt;a href="http://jonas-lieb.de/"&amp;gt;Jonas&amp;lt;/a&amp;gt;&amp;amp;lsquo; (said buddy) first and my semi-first venture into the realms of networked programming. Both of us already used some high level network classes (e.g. Qt) and used BSD-Sockets a few times. I actually worked on a LAN-multiplayer-game recently, but didn&amp;amp;rsquo;t get very far (moving and shooting and infrastucture without any optimizations or compensations). Just to start off we decided not to use ANYTHING remotely hard or an own reliabilty layer (to any extent whatsoever) (this has to be done some time though), client side prediction, lag compensation or proper interpolation and not surprisingly and very much to our liking this is more than appropriate over LAN. Very rarely though essential initilization packets don&amp;amp;rsquo;t reach the client (or the server respectively) (for example handshake packets or map changes) so we somehow have to implement a reliable layer on our own or switch to ENet, which I used in mentioned former networked game. Apart from this we tried to reduce the rather jaggy movement by exponential interpolation (I&amp;amp;rsquo;m not sure if it&amp;amp;rsquo;s called like this - &amp;lt;code&amp;gt;position += c * (target - position)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;c in [0,1]&amp;lt;/code&amp;gt;).&amp;lt;/p&amp;gt;
&amp;lt;h3 id="collision"&amp;gt;Collision&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;Fortunately we had the triangulated polygons at hand and just had to implement Seperating Axis Theorem. There was only one thing we &amp;lt;span style="text-decoration: underline;"&amp;gt;really&amp;lt;/span&amp;gt; struggled with for quite a long time, which is minimal translation vectors that, for reasons we didn&amp;amp;rsquo;t really understand, pointed in the wrong direction. We decided to just flip them if they pointed along the vector between the two polygons center of masses (cosine of inner angle &amp;amp;lt; 90° &amp;amp;lt;=&amp;amp;gt; dot product &amp;amp;gt; 0)&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Sorry for not really telling you interesting stuff, but this should be more of a documentary, rather than lessons.&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>Feedback Effect</title>
        
        <link href="https://joelschumacher.de/posts/feedback-effect"/>
        <id>https://joelschumacher.de/posts/feedback-effect</id>
        <updated>2013-01-29T12:00:00+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;I played around with an old demoscene effect often called &amp;amp;ldquo;feedback&amp;amp;rdquo;. It probably happend to you, that you forgot the glClear (or equivalent clear screen commands) at the beginning of your renderloop which lead you to very funny results. This effect is essentially this but kicked up a notch.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;A video first:
&amp;lt;center&amp;gt;&amp;lt;iframe width="560" height="315" src="https://www.youtube.com/embed/AiWi9A39LxU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&amp;lt;/center&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The code is a mess, so I just present some pseudo-code:&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;
    &amp;lt;li&amp;gt;Set render target to texture "fboTex"&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Add a translation to the transforms (I used my own "continousRandom", which returns an interpolated value from a buffer of random values and polar coordinates (an angle and a magnitude), so the translation changes, but randomly and continuous)&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Add a scaling to the transforms with a little more than screen size (in my example 1.011 times)&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Set color (you have to keep in mind, that having 0.5 as the red channel for example results in having half of the red in the next frame, and fourth in the next, and eighth in the next and so fort, so the values are very close to one and very hard to tweak) (I used: 0.999, 0.995, 0.1, 1.0)&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Render a quad with fboTex (the last frame)&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Just render the image you want to effectify (In my case an image which said "screensaver" using a cool font)&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Render fboTex to screen&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;</content>
    </entry>
    
    <entry>
        <title>Global Game Jam - Cardiac Murmur</title>
        
        <link href="https://joelschumacher.de/posts/global-game-jam-cardiac-murmur"/>
        <id>https://joelschumacher.de/posts/global-game-jam-cardiac-murmur</id>
        <updated>2013-01-28T23:04:00+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;Last weekend I was attending the global game jam in cologne and I have to say that it was a really cool experience! Sadly my team mostly consisted of people from the design school this event took place in (they didn&amp;amp;rsquo;t study game design though) and they had to take part in this to receive certain credit points or something (in essence: My team was 60% people that have never made a game, don&amp;amp;rsquo;t play games and have no skills whatsoever to actively partake in making one) and we weren&amp;amp;rsquo;t lucky to incorporate an artist into our team, so we essentially ended up with two programmers. But otherwise it was still very cool! I was overwhelmed by all these productive talented people and all the awesome ideas. The theme of the game jam was the sound of a heartbeat (the actual sound. Not the description I just gave) and after a bit of brainstorming we decided to make a game where you had to listen to your heart. A kind of parallel-world-gameplay where you had to switch you view to see what your heart was telling you. We wanted to partake in the &amp;amp;ldquo;Games for Change&amp;amp;rdquo;-challenge and make a game that raises awareness of us often overlooking problems of the people surrounding us (not just by being ignorant, but because they try to hide). At first we wanted to focus on characters and their developement and stories. People you are friends with that secretly hide depression or family problems, but we ended up with not enough time and just made a cool platforming-level and one level that merely touched what we had planned. Still I am very content with what we did. I look at it as a prototype of a game that we might make some time.
Link: &amp;lt;a href="https://web.archive.org/web/20130522133503/http://globalgamejam.org/2013/cardiac-murmur"&amp;gt;Global Game Jam - Project Site - Cardiac Murmur&amp;lt;/a&amp;gt; &amp;lt;strong&amp;gt;(Update 7th of April 2015: this link seems to be broken. I added Screenshots and a Download-Link at the end of this page)&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Technical stuff:
The paper-like look is achieved by a multiplied gradient from top-left to bottom-right and a &amp;amp;ldquo;stencil-sketch&amp;amp;rdquo; texture multiplied, which essentially is a noise-texture that is stretched in one direction to have little lines.
The normal world is encoded in the red-channel of the sprites and the heart-mode-version is encoded in the green channel. In a shader these channels are linearly interpolated with a game-defined value and converted to greyscale. We made the maps with &amp;lt;a href="http://www.mapeditor.org/"&amp;gt;Tiled&amp;lt;/a&amp;gt;, which is a great tool and I really recommend you using it (I certainly will use it again) and a little python script to convert them map files to a binary format and splice the tilemaps.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;span style="text-decoration: underline;"&amp;gt;&amp;lt;strong&amp;gt;Update 7th of April 2015:&amp;lt;/strong&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="https://www.dropbox.com/s/4gsz7hi6dk1q4ro/CardiacMurmur.zip?dl=0"&amp;gt;Download link&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="https://youtu.be/M3AxFZOEyYc"&amp;gt;Youtube link&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;img alt="Cardiac Murmur Light" src="/images/cardiac_murmur_screenshot_light.png" /&amp;gt;
&amp;lt;img alt="Cardiac Murmur Dark" src="/images/cardiac_murmur_screenshot_dark.png" /&amp;gt;&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>Species X</title>
        
        <link href="https://joelschumacher.de/posts/species-x"/>
        <id>https://joelschumacher.de/posts/species-x</id>
        <updated>2012-09-01T19:52:00+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;I tried to make a game for ludum dare #24. The theme was evolution and I decided to make a game about some sort of species that evolves and you would have to fight. Because I was in a hurry and I&amp;amp;rsquo;m not very good at such things I ended up with this game. It features a cellular automaton resembling a fungus that spreads through the level and sort of &amp;amp;ldquo;zombifies&amp;amp;rdquo; people and hopefully other living beings (not yet implemented. Neither in my entry nor in the current version), making them slaves to spread the infection further. The goal would be destroying the fungus and surviving the attacks of the evil fungus-slaves surrounding it. Unfortunately the game around this idea emerged to a be a top-down shooter and all in all just way to complex to choose for a 48 hour competition. In short: The game I entered was extraordinarily bad. Really, really bad. I recommend trying it though for comparison:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href="http://www.ludumdare.com/compo/ludum-dare-24/?action=preview&amp;amp;amp;uid=14778"&amp;gt;http://www.ludumdare.com/compo/ludum-dare-24/?action=preview&amp;amp;amp;uid=14778&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;(Screenshot and download link inside)&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;I was so unsatisfied and unhappy with my entry that I decided to see it as my honour to make this game an enjoyable experience. It proved to not be that trivial on numerous occasions but I think I made quite a bit of progress up until now.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;You can find it here:&amp;lt;br /&amp;gt;&amp;lt;a href="https://dl.dropbox.com/u/9961608/SpeciesX_new_and_improved_alpha.zip"&amp;gt;https://dl.dropbox.com/u/9961608/SpeciesX_new_and_improved_alpha.zip&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Screenshot:
&amp;lt;img alt="Species X Screenshot" src="/images/species_x_screenshot.png" /&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;(Note: Space triggers a flame-thrower-effect that has no impact on the game world but looks nice and I&amp;amp;rsquo;m thinking about adding a flame-thrower as a new weapon (or 30-seconds-ish super power up)) &amp;lt;br /&amp;gt;At first you might notice, that the first version was WAY harder. I am pretty sure that it&amp;amp;rsquo;s safe to say that it&amp;amp;rsquo;s impossible to complete a level. Mainly because the enemies would spawn everywhere constantly. So right after sleeping and waking up the next morning I only allowed enemies to spawn if they would spawn on a tile that&amp;amp;rsquo;s currently visible and adjusted the rate of enemies spawning, which changed the experience &amp;lt;b&amp;gt;a lot&amp;lt;/b&amp;gt;.&amp;lt;br /&amp;gt;You feel way less overwhelmed and have the feeling of having more overview what&amp;amp;rsquo;s actually happening in the level.&amp;lt;br /&amp;gt;I then changed the controls so you would throw grenades with G instead of changing the weapon, throwing and changing back which appeared to be very inconvenient mid-fight. After adding film grain and various particle effects (blood, goo (when shooting the fungus roots) and little sparkles (spores, I&amp;amp;rsquo;d say) over the fungus and a cheap fire during a grenade explosion) the next big problem would have been the absolute lack of fun when destroying the fungus. There had to be some sort of satisfaction from destroying it. Until then killing the fungus only meant having to destroy some other fungus somewhere else now. There was no reward. So I decided to change the cellular automaton drastically. I decided that I want to have the regular fungus connected to it&amp;amp;rsquo;s roots. Turning the spot light on the roots, because they deserve it! In the end this connection was implemented in the way that the root fungi dispatched waves through the fungus matter, which get carried on by the regular fungus. Additionally the fungi would die if they weren&amp;amp;rsquo;t &amp;amp;ldquo;freshened up&amp;amp;rdquo; by a wave recently. Also the fungi would now only be able to spread if they are just freshened up. This made the fungus seem way more like something organic and added to the atmosphere drastically.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Still there seems to be a problem with the game being horribly repetitive and just not very interesting. Maybe I have to blow up this game idea with actual progress (different levels, gradually introducing weapons, doors, keys you have to find, generators you have to turn on, stuff like this) to make it interesting, but maybe this is equivalent to saying that this might be a good foundation for top-down 2D horror-shooter. Let me know what you think and how I could improve on this!&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Edit: This is all programmer art! If anyone is interested in replacing some of the images with better ones, I would really appreciate your help!&amp;lt;/p&amp;gt;</content>
    </entry>
    
    <entry>
        <title>First post!</title>
        
        <link href="https://joelschumacher.de/posts/first-post"/>
        <id>https://joelschumacher.de/posts/first-post</id>
        <updated>2012-09-01T18:24:00+0000</updated>
        <content type="html">&amp;lt;p&amp;gt;Hello! I&amp;amp;rsquo;m Joel. I&amp;amp;rsquo;m currently studying physics in Aachen (Germany) and I intend to use this blog as a journal of the games I make in my sparetime (since the next semester starts soon it will probably take quite a while until I post again).&amp;lt;/p&amp;gt;</content>
    </entry>
    
</feed>