Hacker News new | past | comments | ask | show | jobs | submit | more mwkaufma's comments login

On ABZÛ we ripped out multiplayer and lots of other cruft from AActor and UPrimitiveComponent - dropping builtin overlap events, which are a kind of anti pattern anyway, not only saved RAM but cut a lot of ghost reads/writes.


Thank you for ABZÛ! My daughter has played it at least ten times. And when she wrote a letter to your team for a school project, you sent back a t-shirt and a soundtrack CD. We've listened to that CD for hours on road trips, it is a great soundtrack.


Whoa! Didn't picture myself seeing a dev who worked on Abzu in the wild here on HN--I very much enjoyed that game, my thanks and high fives to your team for your work!

I'm having a kid-in-the-tunnel-meeting-Mean-Joe-Green-in-the-commercial moment, I just started my own game development journey about a week ago so it's neat getting to run across a full-on developer!

To stay on topic, I often thought how cool Abzu would have been with multiplayer but it's a good lesson to me that some features that might be desirable might also be a hindrance to some degree.

Okay, enough fanboying!


Oh, nice to see that there are real-life examples of this stuff, thank you very much :) Needless to say that I'll take a deeper look at the overlaps now :D


Your presence inspired me to try to look up what the circumflex on "abzû" is supposed to signify. As best I can tell, it's a marker of vowel length.

I wonder how that came to be used. It's a traditional way to distinguish eta and omega in transliteration from Greek, but it's not at all a traditional way to mark long vowels in general.

(I see that wikipedia says this about Akkadian:

> Long vowels are transliterated with a macron (ā, ē, ī, ū) or a circumflex (â, ê, î, û), the latter being used for long vowels arising from the contraction of vowels in hiatus.

But it seems odd for an independent root to contain a contracted double vowel. And the page "Abzu" has the circumflex on the Sumerian transliteration too.)


Seems to be an older convention in linguistics. Romanizations of Japanese also switched from circumflexes (Tôkyô) to macrons (Tōkyō) at some point in time fairly long ago—I think the English-language Japanese journal I saw using that convention systematically was from the late 1950s, and its recent issues definitely don’t use it.

Perhaps a circumflex was easier to typeset, like with logicians switching from Ā to ¬A and the Chomskyan school in linguistics switching from X-bar and X-double-bar to X' and XP?


"Abzu" is also the Greek onomatopoeia for a sneeze.


I was highly amused to learn that the ancient Greek verb for spitting is πτύω. (Compare English "ptooey".)


Yeah, and the modern is much the same ("φτύνω"). I'm sure it's onomatopoeic, and it's an amusing word.


It's funny how I can sort-of read the Dutch word in "τύν": spit "tuf" and spitting "tuffen". I can't find the etymology of it so it might be a false cognate

If it isn't a false cognate, I wonder what the function of "φ" and "ω" are..


It is a false cognafe, it's not pronounced "oo", but "ee". It's just onomatopoeia, that's why it's so similar.


Mandarin is 吐 /tʰu/.


We pronounce it t-uh-f, as in "tough" without the o.


Note that ν is an N, not a V. I think the standard transliteration of φτύνω from modern Greek would be "ftino".

(Note also that "tough" is pronounced t-uh-f /tʌf/, with nothing O-like anywhere in it.)


I wonder if that's because of the two different ways you can spit: without windup ("tuf" sound) and with windup / breathing in ("hff-tuf" sound).


Does the popular 'hawk' prefix for this also originate from ancient Greek ?


What's a ghost read? Search engines are failing me.


There's two main things. First of all, when you load data into a register from an address in memory the CPU loads 64-byte cache lines, not words or bytes. AActor for instance is 1016 bytes. 16 cache lines. It's freaking huge.

So let's say you're going through all the actors and updating one thing. If those actors are in an array it's easy. Just a for loop, update the member variable, done. Easy, fast, should be performant right? But each time you're updating one of those the prefetcher is also bringing in extra lines, more data in the object, thinking you might need them next. So if you're only updating a single thing or a couple of things in the object on different cache lines you might really bring in 3-8x the data you actually need.

CPU prefetchers have something called stride detectors which can detect access patterns of N number of steps and stop the prefetcher from grabbing additional lines but at 16 cache lines the AActor object is way too big for the stride detector to keep up with. So you stride in gaps of 16 cache lines at a time through memory and you still get 2-3 extra cache lines after the initial access.

Secondly, a 1016 byte object just doesn't fit. It's word aligned but it's not cache line aligned and it's sure as hell not page aligned.

Best case scenario if you're updating two variables next to each other in memory the prefetcher gets both on the same cache line. Medium case scenario, the prefetcher has to grab the next line every so often. You'll get best most often and medium rarely.

Bad case scenario, the prefetcher has to grab the next cache line on the NEXT PAGE. Which only just became a thing on recent CPUs but also involves translating the virtual address of the next page to its physical page address which takes forever in data access terms. Bunch of pointer chasing, basically a few thousand clock of waiting.

The absolute worst case scenario is that the prefetcher thinks you need the next cache line, it's on the next page, it does the rigamarole of translating the next page's virtual address and you don't actually need it. You've done two orders of magnitude more work than reading a single variable for literally nothing.

So yeah. The prefetcher can do some weird ass shit when you throw weird and massive data structs at it. Slashing and burning the size down helps because the stride detector can start functioning again when the object is small enough. If it can be kept to a multiple of 64 bytes you even get page aligned again.


*an exponent of 64 bytes

If it can be kept to a exponent of 64 bytes you even get page aligned again.


Unused memory accesses thrashing cache


Unnecessary reads that you can’t really control or observe well.


What makes overlap events an anti-pattern?


In principle it's a fine idea, but their implementation has so many footguns (race conditions, thundering herds, perf cliffs, etc) it was easier to impl your own simpler alternative.


It's a bit legacy, since it's just used to tesselate PhysX/Chaos trimesh collision, rather than doing true BSP collision in game :/


Last year was rough for indie funding because of interest rates. Luckily, Absolute Nothing Economically Destabilizing Is Happening This Time (O___o).


That's a cool reference, thanks for showing me. Similar energy to Q1K3 https://phoboslab.org/log/2021/09/q1k3-making-of


It's not a BSP, it's volumetric data (this is in the actual article). Just off the bat I get aerial navigation "for free" without having to hand-place regions, and a secondary collision-query for bullet-hell that's much faster than Chaos, which was a huge perf regression in UE5 from PhysX (which already wasn't great).

Additionally, there's productivity + rapid iteratoin. Trying to build interiors with Unreal's built in drag-out-an-actor-at-time interface is too laborious, and the built-in automations (Construction Scripts, Blutilities, PCG) are impedance-mismatched for constructing interiors quickly.


I don't think I quite understood what you are trying to accomplish that is distinct from what 90s BSP engines like Unreal 1, Quake 2, and Source were doing?

Are you trying to do convex spatial partitions for 3d pathfinding in the air?

I did an indie VR starfighter game Rogue Stargun (https://roguestargun.com) and quite honestly intermittent navigation raycasts from the enemy ship AI is sufficient for this sort of stuff.

The bullets all run on the main thread on mobile hardware and so does all the AI. It's not optimized and I have yet to witness CPU bottlenecks being the main cause of frame drops.

Your game looks simple enough and is on the PC platform... I suspect you may be optimizing for the wrong thing.


Target is switch/steam deck, and I have hard profiling numbers on fully decked scenes, so your suspicions are inaccurate.


How is it that you are running into cpu limitations for raycasts in a bullet hell game with UE5 to the extent you built this?

I wrote a VR game that has hundreds of bullets running at 72 fps on Quest 2. Never went multithreaded and never actually encountered FPS drops due to CPU limitations


Can't tell you wo a profile, but I assume your content was as complex as a full byzantine shooter map. I've also got large enemy squads, so there's an M×N issue.


A whistle-stop tour of some game-engine collision/pathfinding background, how modern engines work, how old engines work, and how I'm applying a mixed-approach in my game.


Excellent article, and I appreciate how you gave an overview of solutions that didn't make sense for you but were otherwise important to know about.

Could you expand on how your pathfinding works for both ground-based and flying enemies? I've been trying to wrap my head around how to handle this on my own game, and trying not to invent a wholly separate solution for enemies than can avoid obstacles vertically.


The scaffolding is built from convex volumes, and I know which cuboid faces are "walls" and which are "windows" so I link the windows into a graph where the shared-faces are waypoints and do A*, using straight-line distance as the cost function.

Big obstacles are just built from the scaffold itself, and small obstacles are avoidable by just doing "whisker-traces" to veer around them (the navigation path is a movement hint used to calculate accelerations, not followed strictly).


Given a long enough path, does this lead to enemies always flying through the center of “windows”?


Not OP but hobby gamedev here:

Yes, but that's why ~~good~~ fun enemy AI for games is both an art and a science.

My approach is that the path from the pathfinding algorithm is just a known good solution. The path the agent gets back from the algorithm doesn't have to be just a list of Vector3's for the window centers. It could get back a list of each window quad instead, and then aim for a random point in the next quad shifted by the distance between the two quads. You can also do some raycasts from each agent occasionally to do local-avoidance-type behavior (which you'll likely have to do anyway so that enemies spread out a bit and avoid non-static geometry).


I'd also ask if this isn't somewhat accurate for how people would do things? We have specific rules that we have internalized on what side of a road to drive on. But, absent those rules, it isn't uncommon to just drive down the center of the road. Largely expected on many surface streets that don't have brightly painted lanes and large shoulders.

To that end, you could always encode the rule of what side of a window to aim for? Something you probably want to do if you are going to be aiming for bidirectional agents going through them?


They did in my janky initial impl, but in the current version waypoint interfacing "windows" are now quads.


I have such an appreciation for write ups like this. Reminds me I'm not a real programmer at all.


Wait, his "graph" measures a greater gamut of colors in photos from the nineteenth century when they were all B/W? Who's still buying this retvrn hucksterism?


Current photos of old objects. I admit I had the same question based on the caption included in the graph itself, which just says "photos."

> a study of over 7,000 objects in the UK’s Science Museum found that the colors of consumer goods have been steadily neutralized since 1800. Bright, saturated tones have been giving way to gray, beige, and taupe for centuries.


The graph is from a study of objects held in the collection of a museum, not photographs by year they were taken. It says so in this article.

https://lab.sciencemuseum.org.uk/colour-shape-using-computer...


Yeah you're right, I jumped the gun there. On the other hand, color trends of science museum exhibits are a cherry-picked example. "Culture Critic"'s whole shtick is to put a photo of a modernist building next to an ornamental one, and this just seems to be that, but with a superficial layer of scientism.


Personally I think the collection used is pretty good, not perfect but not cherry picking. I find CC's explanation unsatisfactory and loose, mostly placing the blame on philosphers that predate the recent trend of less color by decades or millennia, and skipping over well known major events in the history of color fashion. But I do agree that ornamentation and color are less common today in architecture and product design than they were in prior decades, and than they were for much of history. Except perhaps for a narrow band of blue.

https://en.m.wikipedia.org/wiki/Great_Male_Renunciation


Nothing smells like bullshit quite like a data-less "graph"


Instead of billionaire-directed patronage, just tax wealth and let the democratic process decide how to allocate it.


The US (and UK) have been growing enormously in wealth inequality. This is the big actual problem wealth needs to be distributed more evenly as its harming many people. I think there are a lot of arguments for which mechanism is used, whether its inheritance or direct wealth tax or capital gains or something else, but the obvious cause of the problems today is inequality and that needs to be addressed.


> wealth needs to be distributed more evenly as its harming many people

Why? Seriously. I used to believe this. But it’s increasingly apparent that a lot of people are idiots. Why is inequality in wealth fundamentally bad if the poorest are taken care of? (They’re not, in America. But I’m framing a hypothetical.)

If a UBI proposal requires dismissing the concept of waste, it’s probably a stupid one.


One reason is that the intensely wealthy class doesn't simply spend their fortunes on more food or more sheds to store more lawnmowers or extra rice cookers or patronize more local businesses across the country. They might buy more beds for their now larger mansions, but their rate of consumption doesn't scale linearly with their wealth beyond the median. I seriously doubt they're commonly buying even 12 to 20 yachts, and if they buy 45 cars they aren't driving them enough to also be buying 45 times the maintenance since you can't drive more than one car at once.

Instead they invest their fortunes into private equity and other capital like homes that, after driving the cost upwards, will now rent to the people who are, economically speaking, incomprehensibly far beneath them. They will acquire hospitals, doctor's practices, homes, drug rehab facilities, banking institutions, water utilities and electrical companies to fuel their own wealth. They squeeze out the stakeholder in preference for shareholders who will demand stock buybacks to provide additional returns on investment.

The result is that the people who are on the losing end of wealth inequality will have no voice in how the resources are deployed, the cost of the utility provided, or the capital to compete in the market. It drives the cost of inelastic supply upwards as its utility is no longer a home but an investment vehicle. Generational wealth like farms become corporations which pay their profits to someone other than their local community. National banks squeeze out local institutions with stake in their local economies, they will burn cash to buy the market out from local economies and the profits of life vanish from the people who live it. When there is nothing left to buy, they'll buy the government.

UBI, GMI are bandages for gaping wounds.


I agree. The arguments for UBI can’t be economic because it isn’t economy. The arguments have to be democratic. This also sustains why it must be federal or perhaps at the state level, versus municipal.


> but the obvious cause of the problems today is inequality

This isn't obvious, at all. In fact, it's the main point of contention in many studies talking about income and taxes.


There should be votes for de-selection through the annual possibility of an 'ostracism', in which citizens could write down any name and the 'winner' should pay 95% tax.


You no doubt thought that the only thing wrong with Maoist struggle sessions is that not enough people were their targets.


One year of 95% tax is arguably still not enough.

If taxes on income were rated by wealth, we could consistently tax billionaires 95% tax and they would still be pocketing millions for safe investment returns


That assumes billionaires don't have billions of free speech to hand out to politicians. How many billions of dollars of free speech do you and I have to counter them?


No, you assumed that.


Despite the high frequency that alarmist "formatting you HDD" is cited in discussing UB, I've never seen it happen. Surely there exist real examples of catastrophic failures which could actually teach us something, beyond making a hyperbolic point.


It was intentionally hyperbolic tongue in cheek and understood to be as such. The reason is to fight through the discounting people (at least at the time) had that UB was just a segfault or something. Here’s a kernel exploit that was a result of UB [1]. It’s not hard to imagine that hypothetically UB in the kernel could result in “just so” corruption that would call the “format your HDD routine” even if in practice it’s extremely unlikely (& forensically it would basically be impossible to prove that it was UB that caused it).

https://lwn.net/Articles/342330/


One example is control flow bending [0], which uses carefully crafted undefined behavior to "bend" the CFG into arbitrary, turing complete shapes despite CFI protections. The author abused this to implement tic tac toe in a single call to printf for a prior obfuscated C contest [1].

Of course, that misses the real point that "formatting your HDD" is simply an allowed possibility rather than a factual statement on the consequences.

[0] https://www.usenix.org/conference/usenixsecurity15/technical...

[1] https://www.ioccc.org/2020/carlini/index.html


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: