Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - Simon

Pages: [1] 2 3 ... 281
Lix Levels / Re: Miris Multiplayer levels
« on: July 18, 2024, 12:12:20 AM »
Thanks! Happy to hear that you and your brothers like the shorter building section.

The 4-player version will be asymmetric, but that doesn't mean that it's imbalanced. On first sight, I can't tell if the top exit or bottom exit has an advantage. You've got a reasonable chance that it's pretty balanced!

If you and Miri agree, I'll include both maps (2-player and 4-player Rainbow Day) into the next Lix release. If it turns out imbalanced, we can always fix it later.

-- Simon

Lix Levels / Re: Blitzs Multiplayer Levels
« on: July 18, 2024, 12:07:17 AM »
Now it's like Selective Rescue, except that it's imbalanced and longer.

You've removed the cage, which certainly had its problems (walls too high, nasty squeeze at the top), but it was the unique feature of your level.

What's the fundamental idea of your level? Why should we play it instead of, e.g., Selective Rescue, or Rescue Ranger Trolls? Is it the cage where you free at least one other team whenever you free yours? Example: For 5 players, you might put 5 cages, one for players A and B, one for players B and C, one for players C and D, one for players D and E, and the last one for players E and A. That would be something new that sets your map apart. And you can make such a map completely balanced, by placing the exits accordingly.

But it can also be something else, anything you like. You get to decide! Find an idea and let it be your inner light during map design.

No worries if you struggle with English sometimes. Keep it up! Lemmings Forums (or any English online community about your hobbies) is an excellent way to improve English over what one learns in school. It's how I've been improving my English for 20 years: Relentless reading about games on the internet, and writing posts in English web forums.

-- Simon

Lix Levels / Re: Miris Multiplayer levels
« on: July 13, 2024, 08:19:51 PM »
I had given the map more Builders

Your most recently attached version (Miri Multiplayer Level more still has 20 builders.

I can increase the builders to 50 myself. Although: With strong players, you'll always have saboteurs near your exit, and sabotage by removing terrain is easier than adding terrain. If you want to be really safe, let's increase the builders to 80.

I still warmly recommend: Lower the exits! Try it with the exits in the lower half of the level. I've attached a version of Rainbow Day with what I have in mind. This will avoid the dull building. I'm sure other players will like the map better with this shorter building section. This still has a building section where strong players will go all-out to sabotage.

What do you think? I believe others will like it better with the shorter building section.

-- Simon

Lix Levels / Re: Miris Multiplayer levels
« on: July 12, 2024, 11:46:57 PM »

To translate to German, copypaste the post into:

Rainbow Day looks really promising, with lots of fighting in the outside columns after crossing the middle. Thanks!

Why did you put the exit so high, with a steel wall in front? Do you expect people to climb up? Or do you expect people to build up? Building will be boring, and it's near-impossible because you give only 20 builders. Or do you want to make it a race map where you win if you climb one single lix? In this case, cut the overtime from 1:00 to zero (0:00).

Have you played Rainbow Day yourself? How do you usually win: By climbing or by building?

Try it after moving the exit down, e.g., into the lowest one-fourth of the height of the level. I'd keep the overtime at 1:00, but give 50 builders instead of 20. Do you like it better now? If you don't like it, you can always go back to the version you've attached to your first post.

I'm happy to merge Rainbow Day into the main Lix download after you've decided if the exit should be lower or not.

-- Simon

SuperLemmix / Re: [FEAT] Rewind button / hotkey
« on: July 10, 2024, 06:54:32 PM »
The question remains, though - why are we able to perform repeated backskips by pressing and holding a key, without any of the aforementioned issues? [When holding the single-tick rewind key, ] It responds smooth as butter. Why can't Rewind mode also do this?

Your observation in your older message suggests: It's well possible that there are still other problems in the rewind mode that the single-tick rewind doesn't have. It's good to investigate this even before the other concerns.

Assuming your observations still apply to your recent versions, I expect the biggest gains from:
  • (biggest gain) Find the conceptual difference between the one-shot n-tick rewind and rewind mode. Without looking at your codebase, I imagine that it's best for rewind mode to be implemented in terms of the (backend of the) one-shot rewind-n-ticks technology.
  • (also big) Savestate more often.
  • Improve efficiency of a single physics update. Its well possible that there is treasure to be found here, but it may well be deeply buried and expensive to lift.
  • Avoid storing the land twice if two successive savestates have identical land. This may need a conceptual redesign of the savestate collection. I don't do this at all.
  • Improve the size of savestates.
  • Improve efficiency of saving/loading the world in other ways than #4 and #5.
My concern is that keeping more savestates in memory might cause other performance issues...?

This sounds like a classic time-vs-space tradeoff. It's hard to recommend anything but: Implement it one way, measure, then implement it the other way, measure again, and compare.

You can ballpark RAM usage in the OS's standard system monitoring. Should you crash with out-of-memory, you have a clear answer. :devil:

Right, forgetting savestates appropriately becomes an important part of saving more often.

-- Simon

SuperLemmix / Re: [FEAT] Rewind button / hotkey
« on: July 09, 2024, 10:02:17 PM »
There is also the possible optimization with the value-type lemmings. I'm explaining this only for completeness after reading your posted code. Avoid doing this.

I assume the lemming is a heap-allocated class object. The optimization goes as follows: Make the lemming a struct (record) without indirection inside, i.e., no references to other objects inside. This means that you can copy the raw memory (with the Delphi equivalent of C's memcpy) and get a perfectly fine deep copy. Next, you ensure that LemmingList stores the lemmings in contiguous memory (with the Delphi equivalent of C++'s std::vector or most languages' dynamic array, or brazenly allocate raw memory yourself). Then you can copy the raw memory of all lemmings in one go. To create a savestate, you need only one heap allocation for the new dynamic array instead of one allocation per lemming. And the CPU will also be much happier iterating over lemmings in an array than iterating over individually heap-allocated lemmings scattered across the RAM.

This brought me 2 % in 2017/2018. But the 2 % is really compared to my earlier code, not yours. In my earlier code, I had the job (current activity) of the lemming inside the lemming as another heap-allocated object, therefore I got rid of two allocations per lemming, not only one. (I still call virtual methods on the job subobject that's embedded in the lix. I changed only the allocation strategy, not the object-orientation of the physics. :lix-tongue: )

Thus, likely it won't be 2 % for you, and it's not worth the trouble unless you know exactly what you're doing and how you can do it in Delphi. You need a reasonable understanding of what the language and standard library offer.

The same optimization is possible with gadgets, and I assume it brings even less there.

My money is still on savestating more frequently than every 10 seconds.

I edited my previous post: I got 3.5 % out of refactoring away from too many shared pointers and out of immutable gadgets, not out of making the world faster to savestate. I can only measure this properly during mass-replay verification from the command line, where I don't savestate at all. It's possible that there are gains bigger or smaller than 3.5 % in leaner world savestating, but I'm not sure if it's your best bet immediately. I still recommend savestating more frequently, to reduce the amount of forward calculation during rewinding.

-- Simon

Site Discussion / Re: [BUG] Site timeouts when posting
« on: July 09, 2024, 06:01:45 AM »
I haven't ever seen this. General troubleshooting:

  • What OS does the laptop run?
  • What browser did you use?
  • Did you log into the forums via the small login widget on the main site, or via the dedicated login page?
  • Did you pick the permanent login ("Always stay logged in")?
  • "pretty much every time I post", does it also happen when you spend fewer than 5 minutes between opening the post-composing form and submitting the message?
  • After you've received the error about session time-out, are you then still logged into the forums afterwards, or do you have to log in again?
  • After you've received the error about session time-out, does the forum present you a blank post-composing form, or does it pre-fill the form with your previously typed text?
-- Simon

Lix Levels / Re: Blitzs Multiplayer Levels
« on: July 09, 2024, 12:56:10 AM »
Hi! I don't think Cage Rescue is ready for merging yet.

The biggest problem is the long and boring work in the cage. To release your crowd, you'll have to release all crowds with you. This encourages to let others do 100 % of the work in the big cage and save your builders.

There is also an imbalance with the exit positions because there are only two small holes to leave the cage. When your exit is under the middle of the steel cage, it's much harder to reach it. Maybe give everybody two exits, an easy one and a harder one? Or think of more ways to leave the cage. Or arrange the existing exits in other ways than a long row at the bottom. There are many possibilities to make the hard exits easier to reach.

When you only have a hard exit, it's extra bad on Cage Rescue because the map forces you to reach your exit it while you're releasing everybody else. If this is what the map should be about, make the cage shorter vertically, so we get to get to the interesting part of the match much sooner.

It's unnecessarily hard for the crowd to squeeze through the holes at the top. Beginners' builders will cancel near the top. Consider removing the entire ceiling of the cage.

Decorate the level! It needn't become art, but at least put a few more terrain pieces than only the plain steel rectangles.

-- Simon

SuperLemmix / Re: [FEAT] Rewind button / hotkey
« on: July 08, 2024, 04:06:35 PM »
Short answer because busy; prod me for details later.

Making saving/loading of the world faster was only 3.5 % for me woth an unclear amount, possibly more, possibly less than 3.5 % during graphical play. But I'm not sure if it's your best bet to start here. You're aiming for 1.5x or 2x, not 3.5 %.

NL creates savestates every 10 seconds. That doesn't sound frequent enough to me. Create another savestate (either one, or a leapfrogging pair) every 10 physics updates (even faster than 1 second) and replace frequently. Reason: With 10 seconds, I had noticeable lag during rewinding on larger NL maps in Wine on 2016 Intel i5-6600. The lag got better whenever timer was barely past a multiple of 10 seconds, and the lag was worst whenever timer was almost at the next multiple of 10 seconds.

NL takes longer for mass-replay verification than Lix. This suggests that you should investigate forward calculation (a.k.a. advancing physics) in NL/SuperLemmix. Reduce the amount of forward calculation (savestate more frequently) or make forward calculation itself better (unsure if that's good idea, or where to start in NL for that). Speedy rewinding requires speedy forward computation from a savestate behind the scenes unless you savestate every physics update, which you are not.

Compression improves space (RAM) but costs time (during compression and uncompression), I doubt that space is your biggest worry. I'd recommend to try something else first. You can look into compression when your strategy is to keep a truckload of savestates.

-- Simon

Tech & Research / Re: The Direct Drop Topic
« on: July 06, 2024, 09:13:26 PM »
The compelling factor is contact with the trigger, then, rather than lem state or exit position.

Floaters enter the exit trigger from above, too. ;P Anyway, you wrote that floaters are special and we shouldn't care about them here, that's good with me.

You also wrote that you're interested in fallers and splatters only. That's good enough for the research: When a faller can enter without splatting, you get midair direct drop. When a faller-to-splatter or a splatter outright can exit, you get grounded direct drop.

Thanks for showing the Amiga floaters.

-- Simon

Tech & Research / Re: The Direct Drop Topic
« on: July 06, 2024, 11:40:14 AM »
they solved a level using a text editor! :forehead:

I solved it in my head, then wrote a script to generate an NL replay for it, then verified in NL that the replay was a solution, then submitted the replay and the script.

DOS Lemmings 1
unintentionally, as a bi-product of incorrectly handled physics.
I unfortunately wasn't around for a lot of the early Forum discussion

I'm investigating engine behavior, not classifying it as bug. You started a nice table, and I'd be happy to see more entries filled. I'm criticizing your table for distinguishing the wrong things.

This is from DOS Lemmings 1, and clearly we can enter midair exits. Your table says that we cannot directly drop into midair exits in DOS Lemmings 1. I recommend that you distinguish by activity of the lemming, not by groundedness of the exit nor of the lemming.

It may help you to define direct drop in the first place. You've said "it's basically this" and posted an example gif. Fallers don't exit in DOS L1 even when the exit is grounded, they must start splatting first, yet you say that DOS L1 has direct drop for grounded exits. Floaters enter midair exits, yet you say that DOS L1 has no midair direct drop. What is direct drop?

Do you have an Amiga or emulator ready to run Amiga Lemmings 1? What happens when floaters pass a midair exit on Amiga L1?

-- Simon

Today, I've improved replay verification runtime once more by 13 percent. This is unexpectedly good, I didn't want to believe it, and I spent 2 hours to isolate the reason.

The culprit was the code that tests whether lix should exit. This code runs for every lix alive, during every physics update. The old code was:

if the outside world generally allows lix to exit because we aren't nuking
    and this lix has encountered an exit during movement
    and this lix' activity allows to become exiter
    then loop through all exits, give points ...

The new code changes the order of the questions to:
  • Have we encountered exits earlier during this physics update?
  • Does our activity allow us to become exiter?
  • Is it generally allowed to exit because we aren't nuking?
Asking for encountered exits first has two desirable qualities:
  • It's usually false. The logic can short-circuit, i.e., we can skip the remainig questions.
  • It's fast. The lix stores her encounters in a small bitfield. We test one bit inside the lix.
Asking the outside world for general exit allowance is the complete opposite: We're usually allowed to exit (rarely are we nuking) and asking the outside world is expensive here. This code runs once per lix per physics update, thus the hot memory is the lix's own memory. Asking the outside world follows a pointer to not-so-hot memory, and we compute the answer (are we nuking) from several properties of the player teams.

Reordering three lines brought a whopping 13 percent speed improvement during mass replay verification. This means 13 percent of the entire workload -- which includes file loading, terrain rendering, ... I'm sure it will be useful during graphical play, too, especially when we compute several physics updates behind the scenes during networking games or during singleplayer framestepping.

There is treasure everywhere!

Nonetheless, I don't want to believe it still. 13 percent sounds too good. I'll have to playtest this experimental build in a networking session first.

-- Simon

Tech & Research / Re: The Direct Drop Topic
« on: July 04, 2024, 06:57:33 AM »
This is really 3 topics rolled into one: Physics research across engines, interpretation across engines, and design of SuperLemmix. I'll focus on the research here.

The distinction between mid-air exiting and grounded exiting isn't perfect. It's better to distinguish
  • by lemming activity first,
  • possibly by activity transition if research points us to it,
  • and only by lemming groundedness if we can't explain it purely by activity.
Reason: In DOS Lemmings 1, the knowledge is that fallers don't exit, splatters don't exit, but fallers-turning-into-splatters may exit during this exact physics update. The groundedness is irrelevant for exiting; it merely prompted the faller to splat. Strictly, this irrelevance of groundedness is unverifiable by experiment; Occham's razor tells us to consider it irrelevant until we know better. At the very least, the groundedness wouldn't allow splatters to exit either after the splatter has missed his one-frame chance to exit.

More activities of interest:
  • Floating. IIRC, floaters in DOS Lemmings 1 exit in mid-air outright. The devs prevented fallers from exiting, but not floaters. NL behaves the same, floaters exit mid-air, but fallers don't. What do floaters in Amiga L1 do?
  • Climbing. DOS Lemmings 1 climbers are inside the wall, thus grounded (which I claim irrelevant), but otherwise similar to floaters (can't assign most skills). Can they exit mid-climb? I expect that climbers can indeed exit in DOS Lemmings 1.
  • Drowning lemmings after they have started to drown. In DOS, they don't exit. But they move. On which engines can you drift horizontally into an exit as you drown?
  • Drowning lemmings exactly during transition from falling to drowning. This will be interesting in DOS Lemmings 1: Like faller-to-splatter, it's a transition between two un-exitable activities, and we already know that faller-to-splatter may exit.
  • Burning lemmings, exactly during transition.
  • Theoretically, one can investigate hoisters, blockers, ..., but I feel that that these provide bonus knowledge only. They're not as crucial when you want to apply the knowledge later to interpretation or design. They're also harder to test, e.g., in DOS Lemmings 1, you'll have to move an exit trigger area onto a blocker via a falling oh-noer.
-- Simon

Lix Main / Performance of Rewinding and of Mass Replay Verification
« on: July 03, 2024, 01:24:28 AM »

after Mindless released Golems on the forums here, he posted his ideas about what to include in a savestate, what to compress, ... I got inspired to investigate Lix rewinding performance. Over several evenings, I've finished the following three improvements:
  • Savestate only the mutable half of the world
  • Choose graphical frames of hatches/exits/... only when drawing
  • Refactor away from overuse of shared pointer to world
1. Mutable Half: The world in Lix consists of terrain, players, their lix, hatches, exits, traps, ..., and I used to keep everything in savestates. But some parts of the world never change: Water never changes. Fire hazards never change. An exit has some state (e.g., ownership, the red player gets points) but this state never changes during play. The initial value of the overtime never changes.

I've separated the world into a mutable half (land, lix, triggered traps, ...) and an immutable half (hatches, exits, water, ...). I copy only the mutable half into savestates. When I load a savestate, I attach the loaded mutable half to the existing immutable half, and that's the new world. This makes the savestates smaller in memory and reduces allocations. Each gadget (hatch, exit, trap, ...) is a heap-allocated class object. To track one in a savestate, we must deep-copy it, and it helps when we only have to save some of the gadgets, not all.

The name "half" is euphemistic. The mutable half is still the lion's share with the uncompressed land bitmap, the physics map, ..., and I didn't look into compression.

2. Graphical Frames: Ostensibly, exits still change over time because they animate. This animation has no bearing on physics, which is a strong argument to keep the exit in the immutable half of the world. But if the exit never changes, it can't keep track of its current animation frame.

The solution: During drawing, I tell the exit the current tick (physics update number) and the exit computes its animation frame from first principles. The drawing method ferries the arguments the to the exit.

Instead of incrementing the frame each tick and resetting the frame after reaching the end, we compute the modulus tick % animationLength. Naively, taking the modulus of integers is slower than adding and comparing integers. But there are performance benefits: We track less state in the exit now, which makes the exit smaller in memory by itself, and it makes all savestates smaller because exits can now be in the immutable half of the world.

Most importantly, non-drawing physics updates don't have to compute animation frames for exits anymore. When we aren't going to draw the results of some physics updates, we've saved many virtual method calls: One virtual call per gadget per update.

After all, we have our direst need for performance during singleplayer rewinding, during networked games with many players, and during mass replay verification. All three cases compute several (or all) physics updates behind the scenes. E.g., rewinding loads a savestate that is older than the target tick, then updates physics forward from the savestate until we're at the target tick.

3. Ditch Shared Pointer: A shared pointer to the world means two levels of indirection:
  • Usercode holds a shared pointer by value.
  • Each shared pointer points to the single reference-counting storage.
  • The reference-counting storage points points to the payload.
Compare this with unique resource handling (one indirection) or putting the world struct by value inside your world-handling code (direct access for the holder, and still one indirection for other parts of the physics).

In 2016, when I wrote D Lix, I chose the shared pointer for all holdings of worlds (the current world and for the savestated worlds) because I wanted easy savestating. The same world could appear several times in the savestating cache. I used the same type (shared pointer to world struct) everywhere. The problem was in the current world, which was also a shared pointer to a world struct. All physics that referenced the world (instead of, e.g., only the lix at hand) had to dereference the shared world pointer many times over.

Solution: Now, I hold the current world by value. After all, the world struct is less than 300 bytes; there is a lot of indirection in the world by itself already.

Sidetracking: I've also removed the shared pointers from the savestating cache. That wasn't necessary to change; it wouldn't have mattered for performance here. For now, I've resorted to manual management of copying/disposing between the current world and the savestates. To do what I really wanted, I need move semantics. D supports C++03-style RAII, but not yet the value-type-based rule-of-five resource handling that became popular with C++11. I want to write my program in the mathematical union of all the programming languages.

Overall Benefit

Mass replay verification is 3.5 percent faster. The 1077 replays from the replay collection take 18.9 seconds on my Intel i5-6600 3.30 GHz. Before, in the stable Lix 0.10.24, they took 19.6 seconds.

It can't be from the smaller savestates because mass replay verification doesn't generate savestates. It must be either from holding the current world by value or from from skipping graphical frame calculations and avoiding their virtual calls. I can't tell which of the two improvements it is, I have only measured all three optimizations together.

During singleplayer, I've kept the full 60 fps more often during hard rewinds when Lix 0.10.24 would dent to 55 or 50 fps. This is hard to quantify because it depends on the level. It's also hard to guess which of the three optimizations played the biggest role here. The bottom line is: The benefit is at least measurable during graphical play.

We'll see if and how much it helps in practice, after I release this in Lix 0.10.25. :lix-smile:

-- Simon

In that light, ditch the belly check.

Ditching the belly check is better, in at least 3 ways, than reintroducing direct drop.
  • It's way more popular.
  • It breaks fewer levels. Direct drop lures designers into offering backroutes.
  • It's not an outright bug in the first place, unlike exits accepting dying* lemmings.
*: At least splatters. I don't know DOS Lemmings 1 exiting behavior of drowners, or of burners, or of already-exploded lemmings. (These already-exploded lemmings are invisible and offset diagonally from their exploding position. They go away after the debris has finished raining. We know about their existence because the cursor opens over them. Their purpose seems to be to prevent the game from exiting to postview after losing all lemmings).

<SimonN> Mindless: In DOS Lemmings 1, exits accept splatters ("direct drop"). Do they accept drowners? Do they accept already-exploded lemmings (they're offset diagonally)?
<SimonN> I can test the exploded lemmings myself in L1. I don't have a test level for drowners.
<Mindless> Drowners and exploders do not exit.
<Mindless> *Technically* splatters do not exit either.  The faller becomes a splatter and then becomes an exiter in the same frame.  Once it has started splatting, it would not exit if the exit suddenly came into existence behind it.

-- Simon

Pages: [1] 2 3 ... 281