something I've always wanted to do with my latest engine was to allow creating a compositional hierarchy of types

a component could construct another component inside it, invisible to the user, making its existence guaranteed

I moved to an actor-component+system design instead where actors are little more than containers of a flat array of components

in practice, component existence isn't that big of a deal

but reuse seems to be much more important

#gamedev #programming

for a while I've been thinking about "the hole problem"

which is - how to synchronize 3 separate objects (2 rooms and a connecting hole) with minimal effort

after a really long time I realized that the inability to use my generated object as a component was the reason why I couldn't put it all together using generated objects

what I needed was instead a component that I could add to doors, which could be set up to generate a hole and sync with walls

#gamedev #programming

in the short term I can do my usual ugly workaround - a new specialized mesh generator object that generates a quad strip based on a polygon and 2 planes

in the long term, I want to be able to reuse a [mesh] component with matching ownership so that I don't have several components that derive from some half-finished almost-mesh component in the hierarchy

matching ownership also eliminates any form of ECS as a valid option (but it's a crap design anyway)

#gamedev #programming

I've been trying to attack the same concept from different angles for a while

apart from the initial prototypes, the first iteration was an asset type that generates whole maps

that was too cumbersome to edit so next I did 2 things (both were good enough to ship a game):

- map editor tools that generated whole map layers (floor plan does this)
- components that generated specialized map elements (e.g. beveled box and countertop)

#gamedev #programming

the current experiment: generated objects

procedurally generated windows used to be a separate editor tool (custom transform controls, difficult to use), now successfully replaced with a generated object type (after shipping)

soon to be replaced with the [building] generated object type, it has all of the same capabilities and many more

however, I'm struggling to fully replace floor plan yet while maintaining the same convenience due to the hole problem

#gamedev #programming

another "side problem" is that decals are currently world-static only

this is because they're generated objects (all of them have the same issue since they generate the whole actor, never just a subset)

it's therefore also impossible to attach GOs to anything that moves

it can be partly mitigated with BGO mesh splitting and actor template inheritance but it should be much easier!

if generated objects were instead components, they could generate their child components

#gamedev #programming

other engines solve this by making everything a node (with a transform)

godot is an extreme example of this, unity is a more relaxed example

I don't like this approach since it ties the transform hierarchy together with the logical hierarchy

the problem is that the transform hierarchy doesn't always match the logical hierarchy

things with pieces that can fall off are a good example

e.g. a car can lose a door but could keep it logically attached (owned)

#gamedev #programming

so that's why one of my future goals is to be able to construct subcomponents inside components

this would allow converting generated objects (building and decal) to components that do the same thing

I'm however not entirely sure what this would do to actors and actor templates - maybe they'd need to be constructible at a component level instead, maybe an actor could just be any component inserted directly into a map, and a group component could have actor's structure

#gamedev #programming

I'm also not sure how to handle component references and searchability within a root group

a flat component array does make searchability very easy

maybe subcomponents could be used only in cases where subcomponent addressability is either not needed or could be done with a path string

local UIDs seem incompatible with the concept of competing allocators anyway

in any case, got some exploratory work to look into, like - how to do subcomponent-compatible registration

#gamedev #programming

while looking into using a mesh component as a subcomponent, I was reminded that a lot of use cases involve lazy-generating meshes

I'm revisiting the idea and thinking that it's not actually that useful to preserve any kind of caching behavior

usually there will be no changes, so one update after serialization should be enough

editor UI can also trigger updates

thirdly, there's runtime changes but those would be clumped together so update can be made explicit there

#gamedev #programming

makes me wonder how much time generally in software is spent on doing lazy updates when it would instead be sufficient to replace them with minimal automation + manual updates

the error case for when something doesn't work is fairly obvious once you get used to it - nothing happened means the update function wasn't called

also, "proper" invalidation requires a custom setter for *everything* with the same invalidation code everywhere - that seems like a ton of code waste as well

#programming

while reviewing old code to figure out where to add the UpdateMesh call, took me a really long time to notice these serialization-adjacent callbacks

never been used, never been needed

they're only useful with fixed-function serialization, which isn't the case here

why were they added? no idea 🤷
are they correctly called? (always and symmetrically) no idea 🤷

removed them (in both component and spawner classes)

#gamedev #programming

another issue with components inside components is the ability to reference subcomponents

fixed-length IDs can be stored on the stack so I really want to avoid string paths

but it may require either having an ID allocator or limiting nesting depth

currently leaning towards the latter since that would be cheaper and should let me keep most of the code (in the short term at least)

in practice depth should be at most 3-4

#gamedev #programming

my first subcomponent experiment - beveled box mesh

got to remove about 60 lines of duplicated and not-completely-synced mesh rendering/query code

is there value in this specific case? not sure yet

maybe I could just inherit from a whole mesh class here and leave the internals exposed - that should save like 50-100 bytes per instance

the ultimate value would be from generating multiple components inside one - but that will require figuring out the ID issue

#gamedev #programming

managed to "lock in", as they say, and write a >400 LOC hole component

it inherits from a mesh component but also has a physics mesh and two polygons (metadata for wall clipping) as subcomponents

still need to make a thing that detects walls from nearby meshes and adjusts side planes to fit them, and some keyboard shortcuts for both that and regenerating nearby objects

also need to consider syncing portals from this component

but it should help with my hole problem

#gamedev #programming

added portal sync to the hole component

it might make sense for it to be done while moving the portal around as well (since portals use absolute coords for speed)

need to think about all the ways hole editing can be streamlined

#gamedev #programming

tweaked the lighting to match light levels on both sides of the portal

makes the texture mapping across the hole look perfectly smooth

also, while testing portal updates, it became clear that the shape of the portal has to match the mesh, otherwise things will look wrong due to room lighting being largely directionless, especially near the hole

unfortunately that might mean that non-rectangle portals might need to be rendered into textures

#enginedev #graphics #programming

added a keyboard shortcut to resync selected actors/components

already much easier to move holes around

now will also need to have a keyboard shortcut for resyncing everything likely intersecting the selection *except* the selection

either that or a shortcut for A automatically followed by B, so that only one keyboard shortcut needs to be invoked for a full update in the correct order

created the combined keyboard shortcut where first the selected thing is updated and afterwards the overlapping things are updated

need to do some integrations soon to see to what extent this might solve the hole problem

#gamedev #programming

added a button to find adjacent aligned faces and copy materials from them

unfortunately the UV mapping cannot be copied over as well so things don't auto-align as perfectly as they did in floor plan (which simply added a quad using the existing floor mapping) but it's a passable first attempt

need to figure out how to share a coord space across systems for UV gen to fix that

still yet to do a proper integration of the hole component in one of the test maps

#gamedev #graphics #programming

the first test done with a "real" (preexisting) map

initial hole setup took some time but actor templates/prefabs will take care of that

found a bunch of issues with AI navigation data and how to generate it

among those - holes need nav.links but I haven't yet provided them

but the nav.links also require 2D portal shape data and I'm moving to 3D

need to think about what's the best approach for moving to 3D before I can do much there, maybe could reuse vis.portals now

#gamedev #programming

while looking into refactoring the navigation system to prepare it for future upgrades, found a "room ID" inside the navigation area component which has existed since 2022-09 (3.5 years ago), basically from way back when I was still messing around with the code and there were no concrete plans to make a specific game yet

turns out it's been shipped despite having no use whatsoever anymore

it was used to place the components in an array for easy lookup

🚮

#gamedev #programming

transferred all nav link (🚮) functions to the portal component

the volume/portal components will probably need to be generalized so that various components could be attached to them, allowing the minimum viable world partitioning definition to be reused as much as possible

in corpo/ghost the overlap was at 100% (visibility volume = sound volume = navigation area = room visit tracker volume = light zone)

I can imagine other cases but divergence is more of an exception

#gamedev #programming

the way those components are currently generalized is that any component that wants to attach to it, has to maintain its own mapping (e.g. volume->nav area) to optimize access

(the other direction is not an issue since the metadata component keeps a reference to the volume/portal)

ideally there's a better (and faster) way but it's unclear what that might be

in the case of nav areas, one may want to have more than one agent type, is that still one component or several?

#gamedev #programming

added the basic hole component to the [make portal] command

it's a bit janky in that I don't have full control over the emitted component, which is a broader thing of how generated objects work

also came up with a possible partial solution to the problem of objects having generated parts

a "rootable" (can be placed in the map directly) object could inherit from a component, thus actors/spawners/prefabs/gen.objects etc. could become special cases of a rootable component

#gamedev #programming

added door holes to my placeholder door prefab that was used in the spatial sound test map

also converted an old "styles" map (plain room styling test)

it's quite a bit of work to convert the rooms by hand and automated conversion probably doesn't pay off for the <20 remaining maps

improving rectangle editing should be universally useful though

thankfully it seems the holes are finally working as intended though - separate objects that I can move around and integrate with 1 keyboard shortcut

added a new projection mode to deal with the issue of putting doors and windows between rooms

projection is basically doing a raycast to figure out where to place an object

there is an invisible volume whose side faces are in the middle between rooms

so I figured that I could just raycast that volume instead of the visible meshes

and the raycasted point is snapped to the edges so that doors (with origin at the bottom) can be quickly and easily placed on the wall-floor edge

#gamedev #ui

added drag handle support to gen.objects, which should also help a bit with porting the data, as well as designing new content

currently only the rectangle supports these but the plan is to add them to some other things (e.g. polygon edges) as well where useful

it is a bit annoying however that editor upgrades are bottlenecked by having many different forms of scene data, which is why I'd like to consolidate them into fewer forms to require less supporting code

#gamedev #programming #ui

Moving from 2D to 3D nav data is always trickier than expected. Those edge cases with portal shapes and height differences pile up fast.