Hi,
This arose from Lix's Replay Insert Mode discussion (https://www.lemmingsforums.net/index.php?topic=6122.msg97649#msg97649). Independently, I discussed the NeoLemmix behavior shortly on my twitch livestream a week ago.
nin10doadict describes the problem well:
The bug is:Quote from: nin10doadict on January 12, 2023, 11:59:28 PMConsider the example:
Phyu 59: Lem 5 gets a basher.
Phyu 60: Lem 6 gets a builder.
If you go back and insert at phyu 59: Lem 6 gets a builder, then depending on whether we're using Lix or Neolemmix we get different behaviors.
In NeoLemmix the previous assignment to Lem 5 at frame 59 is silently overwritten and won't happen anymore. Could have disastrous effects on the rest of the replay; now any other assignments that were dependent on that one will be in unhelpful locations or fail for one reason or another. I find myself manually shuffling through the frames when using replay-insert to ensure I don't accidentally overwrite something, which seems annoying.
NeoLemmix's insert mode ("blue R") is reasonably hard to access: You'll have to map a hotkey to it, remember the hotkey, and conciously decide to use this mode. Thus, the problem won't hit everybody.
But
if you use it, sooner or later, you'll accidentally assign on a same frame and thus ditch a seemingly-random assignment from the middle of your replay. It's a small data loss bug. Granted, it's softened by the ease of recreating the overwritten replay. But it's insidious because you won't notice right away that you overwrote an assignment.
Solution ideas:Quote from: nin10doadict on January 12, 2023, 11:59:28 PMShould the player have to manage this?
Can the game notify the player that an overwrite has occurred with a sound or visual cue?
Should the game prevent the overwrite altogether? If so, can the player force the overwrite anyway with repeated attempts?
I think that the accidental overwrites should be hard or impossible. A dumb, but robust and easy way is: Flat-out disallow the new assignment and keep the old. If we want to be cheap, then give no feedback besides the obvious failure to insert.
namida, how much energy would you want to invest here? I'd happily chew through some UI suggestions if others pipe up here, and maybe I'll have more insights on my own, too.
-- Simon
Given the data loss aspect, I can justify making some alterations to address this, but I'd rather keep it fairly simple.
Same-frame assignments to the same lemming can probably overwrite each other silently and it should be noticeable enough. I believe this will feel like normal replay cancelling. The worst possible annoyance is permanent ability assignment + immediate skill assignment which feels like it should be allowed outright. Or maybe each assignment should discard the future of that lemming, like in Lix, then you have a single answer to all same-lemming questions.
Same-frame assignment to different lemmings: I'm beginning to think that you should allow them.
It's nasty to play around the limitation. I don't know how much to chalk up to UI (we could disallow more glaringly, or warn better) and how much to the fundamental limitation, the gut feeling is that the fundamental limitation weighs more.
It will be possible to make levels that rely on simultaneous assignments, but I don't think that will be a problem in practice. We saw it in Lix once as a joke/proof-of-concept level, and never anybody relied on it since.
If you don't want to allow it, then let's prevent the silent overwriting nonetheless. The constant necessary awareness of the looming silent overwrite feels like writing Python. :lix-scared:
-- Simon
QuoteSame-frame assignment to different lemmings: I'm beginning to think that you should allow them.
A change of this magnitude is out of the question at this stage.
It pretty much comes down to either "keep as is" or "preserve the original assignment instead", possibly with some added visual and/or audio feedback when the collision occurs.
The bug is that assigning a new skill in "Blue R" (Replay Insert) mode silently overwrites any other skill assignments to other lems on that frame. I usually get around this by framestepping forwards and backwards to make sure I'm not going to overwrite an assignment, but - when I think about it - that's a pretty naff thing to have to do.
So, my thoughts are that one of 2 things should happen here, and one of them will be added to the SuperLemmix wish list in due course:
1) The old assignment should be detected, and the new assignment shouldn't be allowed. Now that we have the Assign Fail sound, this sound can be used here to signify that there is some reason the assignment can't be performed on that frame. An onscreen graphic saying "there is already an assignment on this frame" could also be helpful.
2) Both assignments should be allowed. Since Namida has described this as a "change of ... magnitude", I imagine that either it's something that will take a lot of time and effort to implement, or something that could open up the engine to a lot of bugs, or something that just isn't easy to figure out how to do. Since I'm now more familiar with the codebase, I know a bit more about how the replay system works, but not enough to take on something like this without a bit of help.
So, it's really a case of - which do we prefer?
If the former, I can't imagine that being too difficult to set up. Create a new flag whenever a successful assignment is made, and then check for that flag when making new assignments in Replay Insert mode - there's likely a bit more to it than that, but I at least have some idea how to get started.
If the latter, then I'll need help looking at it and figuring out what the first step is. Maybe Simon and I can add it to the list of things we may look at together? Mayba Namida won't mind casting a quick eye over it - if you can get me started, I'll figure out the rest?
Meanwhile, I do need to find ways to make some of the game features a bit more prominent. Onscreen graphics is one way to achieve this, but I'm having a lot of trouble figuring out exactly how to do this. Windows "Show Message" is easy enough, but not very video-gamey. I'll keep looking into it, because there are now several aspects of the game which probably need it.
In this post, I'll assume that SLX will allow simultaneous assignments. Reason: Allowing simultaneous assignments feels like the saner game design when we have powerful inserting/tweaking features.
The first design problem is to decide what the data structure (that is in the replay, that holds all assignments) must offer.
- Do you want to remember an ordering among several same-frame assignments?
- Do you want to allow same-lemming-same-frame assignments in the replay? (This is separate from whether the UI, on assignment, first cuts same-frame-and-future of the same lemming.)
Same-lemming-same-frame can be useful when you eventually add better tweaking, and it so happens that same-lemming assignments temporarily are on the same frame during tweaking. I haven't thought about it much yet.
Lix just allows it all in the replay, and it remembers the ordering. (Reason: Same-lix assignments may come from the network, from different players on the same team.) I allow extreme cases such as 50 bashers, then 20 builders, then 10 floaters, all to the same lix in the same physics update. The result is that the player loses 1 basher, then 49 bashers fail to assign because you can't assign basher to basher, then we start building and queue 19 more builders, and then it becomes a floater and 9 floater assignments fail. Only the basher goes to waste. It's still stange for sure, but this is only about what the data structure should offer. We can solve some problems with good UI, and it's rarely a problem in practice anyway. (The biggest problem in practice is junk assignments that fail after tweaking, and that problem arises independently of (dis)allowing same-lemming-same-frame assignments in the replay.)
Down the road, you'll have to touch the code that reads assignments from the replay and applies them to the physics. Now, with zero-or-one assignments per physics update, NL call that code either once per physics update or not at all in that physics update. With multiple assignments, you'll call it several times per physics update, once for every assignment, in the correct order.
It's possible that NL relies elsewhere on identifying the replay's assignments by frame. Down the road, the frame number won't be unique anymore.
-- Simon
Yead, I'd need help with that...
Let's start with just allowing same-frame assignments to different lems, then - if that works without too many headaches/issues - we can look at same-lem assignments.
Long-term plans are for SLX to have multiplayer, but I'm more likely to make it 2P only (at least to begin with). So even then, multiple assignments to the same lem are less likely to happen/be a problem.
OK, there are no fewer than three separate functions/procedures which handle skill assignment (namely: AssignNewSkill, DoSkillAssignment and ProcessSkillAssignment). There is also a procedure specifically for writing assignments to the Replay (RecordSkillAssignment).
Happily, we already have a check for assignments on the current frame (fDoneAssignmentThisFrame), which returns true when an assignment is successfully made, and false on a normal physics update frame.
I'm getting into a bit of a headspin trying to figure out exactly how it all works, but I'm pretty sure it's all right here in front of me.
So far, I've achieved the following:
I can prevent assignments at any time when using a check for Replay Insert mode by itself - so far so good. However, deploying the aforementioned fDoneAssigmentThisFrame check only prevents assignments on the next consecutive frame (i.e. not the same-frame) after a successful assignment.
Best guess: the game is trying to make the assignment on that next frame before the physics update is actually made, so the check is still returning true. Meanwhile, the check is false on the frame immediately before the assignment, so assignments to any lem are still possible at that point. Here's a graphic to help show what's happening:
(https://i.imgur.com/DkSbQAF.png)
So, this isn't much use, as it turns out. What's needed is a way to check for an assignment on the next frame...
Also, it turns out that ReplayInsert mode is never cancelled once started, unless it's manually cancelled by the player (at least, that's what the Debugger says). This can't be the case, though, because the "R" disappears from the panel. This is, unfortunately, one of those mysteries that this codebase often presents.
I could really use a second pair of eyes on this. I'm pretty sure we can have a solution to this problem pretty quickly.
QuoteBest guess: the game is trying to make the assignment on that next frame before the physics update is actually made
Yes, that should be how it works.
- Game is paused, wait for input between physics updates n and n + 1.
- It's time to advance physics, i.e., to perform physics update n + 1.
- Give the assignments for n + 1 to the lemmings. (Can be 0 assignments, 1 assignment, or, as you envision, more).
- Perform the remaining parts of the physics update that always happen regardless of assignments.
- Game is paused, wait for input between physics updates n + 1 and n + 2.
While the game is between physics updates
n and
n + 1, what is the current physics update?
n or
n + 1? Between which two of my items does the game increase this number?
Quoteflag is true
So, this isn't much use, as it turns out. What's needed is a way to check for an assignment on the next frame...
Have fewer flags. Mutable state is a source of bugs; we want to minimize the amount of mutable state. Instead, write functions that compute the information on demand from replay content, and from necessary-to-have mutable state (number of the physics update).
Last time I looked, the NL game class was big. See what methods you can move from the game class into the replay class (I assume NL has one), e.g., fetch all assignments for a given frame. Then you can call it with whatever frame number that interests you, the current, or the next.
-- Simon
Quote from: Simon on June 27, 2023, 08:52:47 PM
While the game is between physics updates n and n + 1, what is the current physics update? n or n + 1? Between which two of my items does the game increase this number?
I
think IncrementIteration (in LemGame) deals with advancing the frames. But the physics updates themselves are all handled by UpdateLemmings (LemGame) and Application_Idle (GameWindow).
Meanwhile, we have some progress with this topic - I've figured out how to prevent same-frame assignments! :lemcat:
Yes, this isn't the ideal eventual goal, but it's an improvement over the current behaviour of silently overwriting existing assignments, so it will do for now whilst we look for a way to make the ideal happen.
It turns out that the answer lies with the Replay Manager's handling of assignments, rather than the game itself's handling. The Replay Manager already (thankfully) has a way to check for assignments on past, current and future frames. This check is always looking at the existing replay file into which previously-made assignments have already been written, recorded and stored, whereas the aforementioned fDoneAssignmentThisFrame flag doesn't interact with the replay at all, and so has no way of knowing or responding to this information.
So, you were absolutely correct with this:
Quote from: Simon on June 27, 2023, 08:52:47 PM
Have fewer flags ... Instead, write functions that compute the information on demand from replay content, and from necessary-to-have mutable state (number of the physics update).
Turns out such computations already exist within the codebase, thankfully! It was a case of checking
the Replay Manager itself for an assignment at the current frame. The existing check looks for Assignments
and RR changes, so I duplicated it and made a check for Assignments
only (I previously separated out RR changes for a bugfix elsewhere*, so we now have checks for "both", "only Assigments" and "only RR changes").
It works because, somewhat paradoxically, the game needs a way to look into the future for a change on that frame whilst it's backstepping, because backwards skips go further back before heading towards the target frame at Hyper Speed (what a great sentence that was to type! :lemcat:). The game itself can only deal with whatever is currently true at that frame, whereas
the Replay Manager holds the key for checking past and future events.
So, the "don't overwrite, but also don't accept new assignments" behaviour
will be present in the next version of SLX (2.4). The "assign fail" sound plays as well, so it's doubly clear that the assignment can't be made (even if it's not obvious why).
Commit 760e513ff implements this.(If we find a way to accept multiple assignments in the meantime, then of course this will be updated again before release).
*I used the same check in order to fix the bug that caused the RR sound to trigger during backwards skips. The sound was triggering because there
had been a change between Frame 0 and Current Frame, so I needed to say "only trigger the sound if there's a change on the
current frame. So, I separated out this part of the code and made a new check accordingly.
OK, so I'm beginning to look at ways to allow same-frame-different-lem assignments. I agree, this is the best design choice when we have Replay Insert and Editing capabilities. I even think such Replays ought to be play-back-able in Classic Mode, even if they're not creatable there (Replay features are not available in-game, but Replays can be loaded from the preview screen, when in Classic Mode).
Having slept on it, and reading back over the posts, I'm thinking that for now it's preferable to just not allow same-lem-same-frame assignments rather than get into potential headaches with the Replay structure. The only time I can see it being relevant is in a team-game Multiplayer scenario (as outlined by Simon here (https://www.lemmingsforums.net/index.php?topic=6362.msg99416#msg99416)), which SLX is a long way off getting, if ever.
For Multiplayer, I'll far more likely start off with 2-Player battle mode, and might even just leave it there depending on usage/popularity. I like the idea of creating a co-op mode as well, in which the players work together to solve the puzzle or traverse the level map, but even this could be lem-tribe-per-player, so that players aren't making crossover assignments to the same lems anyway.
From there, things will gradually build on what's been implemented at that point, and the need to allow same-frame-same-lem assignments may indeed present itself. But for now, there's no glaring need for it in single-player SuperLemmix, so it's probably not worth the replay complexity at this point.
Different-lem-same-frame, on the other hand, is a no-brainer. Investigating this now...
I think this might be the relevant part of the Replay code that deals with deleting previous assignments:
procedure TReplay.Cut(aLastFrame: Integer; aExpectedSpawnInterval: Integer);
var
NextSI: TReplayChangeSpawnInterval;
procedure DoCut(aList: TReplayItemList; aLastFrameLocal: Integer);
var
i: Integer;
begin
for i := aList.Count-1 downto 0 do
if aList[i].Frame >= aLastFrameLocal then aList.Delete(i);
end;
begin
DoCut(fAssignments, aLastFrame);
NextSI := TReplayChangeSpawnInterval(SpawnIntervalChange[aLastFrame, 0]);
if (NextSI <> nil) and (NextSI.NewSpawnInterval <> aExpectedSpawnInterval) then
DoCut(fSpawnIntervalChanges, aLastFrame)
else
DoCut(fSpawnIntervalChanges, aLastFrame + 1);
if fExpectedCompletionIteration > aLastFrame then
fExpectedCompletionIteration := 0;
fIsModified := true;
end;
Problem is, it doesn't seem to get called anywhere for deleting assignments, only for deleting SI changes...
I don't mind adding "assign fail sound"
as long as it's optional.
QuoteAnd, if we're disallowing skill overwrite in Replay Insert (we should!*)
*We might as well discuss this one here as well, it doesn't need its own topic.
It seems that you have a pretty strong opinion on disallowing skill overwrite replay in insert mode.
I'm aware of that behavior and I sometimes do overwrite skills with intention. The most recent example is; I was playing one of Strato's levels and I used a jumper to cancel a basher to make a little staircase. Later, I realized that I want to save that jumper for the last. So I overwrote the jumper assignment with a shimmier and luckily didn't have to do rest of the solution again.
These things happen rarely so I don't mind too much disallowing it if there's a good reason.
Quote from: ArmaniIt seems that you have a pretty strong opinion on disallowing skill overwrite replay in insert mode.
I'm aware of that behavior and I sometimes do overwrite skills with intention
Maybe we could use a modifier key (Ctrl, Alt, Shift) to overwrite assignments when in Replay Insert mode. Something to try for 1.0?
The point is that it should always be deliberate. The 10% of occasions where we want to overwrite shouldn't be paid for by the 90% of times we don't.
Quote from: Armani on January 23, 2025, 01:06:04 AMyou have a pretty strong strong opinion on disallowing skill overwrite replay in insert mode.
I sometimes do overwrite skills with intention
Interesting that you want to overwrite. Thanks for bringing it up.
Then it's not 100 % clear. See next post. I still believe that no accidental overwrite is better, but I've only read your post now, I haven't slept over it yet.
Older topics for reference:
2023 topic: Replay Insert Mode ("blue R") silently overwrites (https://www.lemmingsforums.net/index.php?topic=6130)
2024 topic: Replay Insert Mode ("blue R") silently overwrites: Decision? (https://www.lemmingsforums.net/index.php?topic=6810)
Quote from: WillLem on January 23, 2025, 03:01:55 AMmodifier key (Ctrl, Alt, Shift) to overwrite assignments
I've already bound fencer to Shift, and I've bound nuke to Ctrl.
-- Simon
The sounds are secondary. Some of this is fundamental input design and we must get it right.
Quote from: Armani on January 23, 2025, 01:06:04 AMThe most recent example
used a jumper to cancel a basher
I overwrote the jumper assignment with a shimmier
This is a same-tick-same-lemming assignment. This overwriting will continue to be allowed. The design in the 2024 topic was:
- Prevent assignment on same tick to different lemming. Reason: This is the problematic accidental overwriting.
- Some feedback for the prevented different-lemming assignment will be nice. Sound is the easiest.
- Allow assignment on same tick to same lemming. This will first erase the old assignment, then write the new. I assume everybody wants this.
- Additionally, when we erase the old assignment, we should also erase all future assignments to the same lemming. (We keep the future of other lemmings.) Lix does this and it seems the best; reason: The future of that same lemming will desync otherwise anyway. namida/WillLem haven't outright said that this is the best, but I'll chalk that up to unfamiliarity with this detail in Lix. Happy to discuss this.
No need for hotkeys. Prevent only what is absolutely necessary: Same-tick-different-lemming.
-- Simon
Okay so disallowing overwrite only applies to same-tick-different-lemming assignment. That's desirable. It's hard to imagine overwriting an assignment to a different lemming being beneficial. Even if it does in some cases, probably it's not worth the risk of accidently canceling another assignment.
Quote4. Additionally, when we erase the old assignment, we should also erase all future assignments to the same lemming. (We keep the future of other lemmings.)
:thumbsup: I'm 100% behind this
If disallowing overwrite is going to happen, this can be a good reason to introduce assign fail sound.
Not being able to assign skill with no indication whatsoever is a bit weird.
Slightly off-topic, but I've always thought lix's replay insert mode is superior to that of NeoLemmix. You can precisely manipulate each assignment, you can cancel each assignment with a single click and it's visually more intuitive in general. I think it's a good idea to discuss about possible changes to replay insert mode sometime in the future.
Allowing assignment to the same lemming is not without its potential for problems, nor is erasing all future assignments for that lemming.
There are still cases where the player might not realise that there is an existing assignment to that same lemming. Those need to be accounted for as well, especially if the plan is to erase all future assignments.
If anything, we'd go from losing a single assignment - "oops, didn't mean to do that!" - to losing every assignment for that lemming. I'm not sure if Replay Insert mode should be that aggressive.
The Replay Editor is a much better candidate for fine tuning assignments; everything is visible at all times, we can add a button to erase all assignments for a particular lemming, etc. Replay Insert mode should be incidental only, and nothing invisible should happen (i.e. erasing future assignments). In fact, that sort of defeats the purpose of Replay Insert mode IMO.
EDIT: To be clear, I understand why future assignments should be deleted if the current one is changed, as they'll all go out of sync. My point is that I don't think overwriting assignments should be allowed at all in Replay Insert mode. Keep it simple and easy for players to understand. Direct them to the Replay Editor (NL equivalent of Lix's tweaker, which we can absolutely look at improving the functionality/visibility of) and let that sort of fine tuning happen there.
Keep it simple, keep it 100% deliberate.
Yeah, I'm also a bit iffy about the idea of erasing all future assignments for the same reasons. Additionally, it might be useful for the player to refer to the future assignments when correcting them - this could especially be the case if a user is attempting to repair a broken replay.
WillLem and namida, thanks for the replies.
I'll be too busy this weekend to write a full-fledged reply on this subject. I'll drill into this again in February. I'll distill the development insights and playtesting experience from 2022-2024.
Quote from: Armani on January 23, 2025, 01:15:11 PMlix's replay insert mode is superior
discuss about possible changes to replay insert mode sometime in the future.
Thanks, that means a lot to me!
The original inspiration was NL's replay editing window. Yes, there is more cross-pollination waiting to happen here, for both NL and Lix.
-- Simon
I think it's important to distinguish between
Replay Insert Mode - this can be thought of as an invisible* cursor function that allows actions to be inserted into the replay without deleting any existing (including future) actions,
and
Replay Editor - NL's equivalent of Lix's Replay Tweaker (which Simon confirmed was inspired by NL's Replay Editor).
They are necessarily different things. I've spend some time updating SLX's Replay Editor, here are the results:
(https://i.imgur.com/8qN41yC.png)
It's now possible to select multiple items. The originally-selected item in the screenshot above is the one at Frame 00152, to Lemming #1. It's possible to select all future actions for that lemming, and then delete them all at the same time. Or, we can delete just one or two of the actions (for instance, if one of the actions is assigning a permanent skill, we might not want to delete that).
It's also possible to jump (i.e. frameskip) to the frame of the selected event. If multiple are selected, we jump to the first event in the selection.
We can do even more to expand this; I'd rather the Replay Editor be the place where we fine-tune replays, let's make it more accessible by adding a panel button for it. Meanwhile, Replay Insert Mode should remain as simple as possible because it's invisible; it should only insert skill actions to fully empty frames, nothing more.
*The blue "R" lets the player know the mode is active, and there are plans to add a blue cursor as well, but the replay actions themselves are not visible in the same way that they are in the Replay Editor, so we shouldn't start deleting/editing them.
We agree that CE should not silently overwrite same-tick-different-lemming.
Now consider same-tick-same-lemming. How does it look in practice?
Lemming A becomes builder in tick 100. We want to assign basher to lemming A for tick 100.
We rewind to the result of tick 99. We select basher in the panel. We click lemming A, and expect lemming A to become basher. Under your proposal (never overwrite), lemming A becomes builder again. This will intuitively feel like a misclick, we failed to tell the computer that we want to assign basher. You can make the feedback more explicit (better sounds, better whatever), and then the program will look like it's telling the player: No, player, you cannot do what you want. I know that you want to bash here. There is builder in the replay, and I've clearly shown you the builder assignment during rewinding, therefore you'll certainly want to overwrite, but I still refuse to give you what you want.
You'll make the normal case rage-inducing!
Quote from: WillLem on January 25, 2025, 07:02:15 AMthe replay actions themselves are not visible
Actions of the same lemming were visible a second ago, during rewinding -- they were the sole reason for my rewinding. There is no
accidental same-tick-same-lemming overwriting to prevent.
For same-tick-
different-lemming, yes, we shouldn't silently overwrite.
The original feature request against NL was to avoid accidental overwriting to
different lemming. namida originally thought: Let's not prevent overwriting because overwriting same-tick-
same-lemming is so useful (source (https://www.lemmingsforums.net/index.php?msg=103108)). It took some discussion to separate same-lemming from different-lemming; neither of us immediately saw the fundamental distinction. But, indeed, one is an accident, the other is useful.
-- Simon
tl;drI agree that allowing deliberate same-frame-same-lemming overwrites is desirable, but I also believe that the potential for accidental overwrites is too high, even for same-frame-same-lemming.
So there is a list of proposed solutions at the bottom of this post.
Quote from: Simon on January 30, 2025, 01:35:09 AMLemming A becomes builder in tick 100. We want to assign basher to lemming A for tick 100.
For this, I'd rather the player use the Replay Editor (Replay Tweaker).
My two main reasons are these:
1) The whole point of Replay Insert mode is that
it preserves all existing replay actions. The fact that it ever allowed overwriting is an oversight bug, which we agree.
And yes, we're now wanting to make the distinction between "different" and "same" to decide whether we should allow overwriting, but even here I strongly think that overwriting should not be allowed
in either case.
2) The Replay Editor provides actual visible feedback of what's happening, i.e. we're deleting the assignment at frame X so that it can be replaced. The Editor allows the player to jump to tha frame, delete the assignment, then return to the game to make the new assignment. More cumbersome, yes, but also definitely deliberate.
Allowing overwriting by simply assigning the new skill is not without its problems. You're referring in your example to the very specific case of zooming in on one lemming, which you know you want to change the assignment for, and then assigning the replacement skill action at the correct frame: I agree that this particular case is desirable and useful.
However, consider these cases where overwriting to the same lemming would be undesirable (and potentially rage-inducing):
* We rewind from frame Z to frame Y because we need to assign a Basher to Lemming A. There exists on that frame a necessary assignment to make Lemming A a Climber. We unknowingly overwrite the Climber assignment. We then skip forward to resume play from frame Z or thereabouts: oh no! all of our other assignments haven't played out correctly because the Climber assignment has been overwritten. And OK, the fix is simple (skip back to some point before frame Y and assign the Climber), but we've had to unnecessarily mess about.
* We rewind from frame Z to frame Y because we need to assign a Platformer to Lemming A instead of a Builder (we've realised we specifically need the Builder at frame Z). We assign the Platformer, but now all assignments following frame Y are out of sync: we forgot that there exist later assignments to Lemming A which aren't playing out correctly because the Platformer made the lemming turn around, whereas the Builder didn't. Or maybe the Lemming didn't turn around, but the Platformer has changed the relative position of the Lemming for the remainder of the Replay.
Both of these are solved by using the Replay Editor instead of relying on the proposed Replay Insert Mode same-frame-same-lemming edge case. Here's another example that unfortunately can't be directly solved by either:
* We rewind from frame Z to frame Y because we need to assign a Climber to Lemming A. We unfortunately rewind to a frame that has some other assignment, but the frameskip is large enough that the result of the assignment wasn't visible during skipping. Or perhaps it's another permaskill assignment, which are always invisible. We don't actually realise that we are overwriting an assignment in this case, it's purely by accident. This seems similar to the first example above, with an important distinction: the intention here is simply to add a permaskill property to the lemming to update its history rather than make a very specific assignment on a very specific frame; the potential for accidents is highest here, then.
However, the Replay Editor is more helpful here, too; the player can skip to the first action performed by that lemming, resume gameplay, and step back a few frames to make the Climber assignment, knowing that there cannot possibly be any other assignment to that lemming on that frame. And, the reliable and consistent "no overwrite" behaviour prevents overwriting some other Lemming's assignment.
Quote from: Simon on January 30, 2025, 01:35:09 AMWe click lemming A, and expect lemming A to become basher. Under your proposal (never overwrite), lemming A becomes builder again. This will intuitively feel like a misclick
We display a panel message "Replay Insert mode doesn't allow overwriting existing assignments" (or maybe something more concise). That and the Assign Fail sound are more than enough feedback to let the player know why the assignment hasn't taken place.
Quote from: Simon on January 30, 2025, 01:35:09 AMthen the program will look like it's telling the player: No, player, you cannot do what you want.
Yes,
because the player is in Replay insert mode, which never allows overwriting: easy to understand, useful for many other things. It's not about disallowing the player to do what they want, it's about reinforcing the player's choice to be in Replay Insert mode and keeping the assignment behaviour consistent. I would be thinking "ah, OK, the game has prevented me from making a potential mistake".
I do have an idea regarding this though, please read on.
Quote from: Simon on January 30, 2025, 01:35:09 AMActions of the same lemming were visible a second ago, during rewinding -- they were the sole reason for my rewinding. There is no accidental same-tick-same-lemming overwriting to prevent.
You're only thinking of one very specific case: the intentional overwrite. See the other potential accidental cases above for where we don't want to overwrite, even to the same lemming.
Proposed solutions:
We can certainly reach a compromise here. I have some ideas, here they are in order of personal preference:
1) We use a definable hotkey to allow overwriting in Replay Insert mode. We accept that this will also allow overwriting to a different lemming, but since the use case is so specific (overwrite to same-frame same-lemming), it's unlikely ever to be an issue. This is by far my favourite solution to the problem, and would be very easy to implement.
2) Allow same-frame same-lemming overwriting, but make it optional. This means that players get to decide how they want Replay Insert mode to behave, and it's always an informed and intentional choice. However, it doesn't allow on-the-fly switching of the option should be player wish to momentarily opt for the other behaviour (this applies either way: "I definitely want to overwrite here" and "Hang on, I'm not sure if there's already an existing assignment on this frame"). It also means figuring out the
how when it comes to implementing same-frame same-lemming overwrite, which (full disclosure) isn't trivial!
3) We introduce a
third mode: Replay Overwrite mode, which behaves like Replay Insert in that it preserves everything it can, but does allow overwriting (so, essentially, the current NL 12.14 version of Replay Insert mode!). Again, the player accepts the potential for accidental overwrites (otherwise, if an assignment is ever not allowed in this mode, the player gets the same rage: "I thought this mode allowed overwriting, why can't I make this assignment on this frame??"). I prefer this solution much less, because Replay Insert mode is already difficult enough for some users to get their head around (hence my strong desire to keep it as simple as possible).
4) We allow overwriting to same-frame same-lemming, but warn the player that they are about to overwrite an existing assignment. This is the worst solution of all, but it does satisfy both your desire to allow the intentional overwrite, and my desire to prevent the accidental overwrite.
Hmm, intentional same-tick-same-lemming assignment is more common than accidental same-tick-same-lemming assignment. But you have a point with how both such overwritings are still not common enough to spearhead the main design of the feature.
Regarding only a single lemming (disregarding same-tick-different-lemming worries), it's more common to kick a lemming's future from a wrong assignment onward, and then insert around that time.
I'll re-read the discussion with this insight and come back to your long post in a few days.
-- Simon
Quote from: WillLem on January 30, 2025, 04:11:02 PMunknowingly overwrite the Climber assignment.
Permanent ability assignments are odd in modern Lemmings.
For the physical motion, there is no difference between
- queuing the climber for the next wall (let the engine assign it for you when lemming reaches wall) and
- assigning climber earlier than the next wall (assign at arbitrary time between two reachings of wall, but you still must choose a tick).
From the view of the replay, it's a difference because NL refuses to accept two assignments for a single physics update. The intuitive fix for insert mode, when the clashing assignment comes, is to shift the old climber assignment earlier/later by 1 tick, in hope that it doesn't produce different physical motion. This is nasty. It's not guaranteed to produce equal motion, and the climber can clash with another old assignment.
I recommend: Don't worry about permanents. Solve the other skills first, then think about permanent abilities. I have worried about this in Lix, too, and it's too rare a case to design the entire feature around it.
Quoteassign a Platformer to Lemming A instead of a Builder
now all assignments following frame Y are out of sync
solved by using the Replay Editor
... or by cutting the same lix's future.
By your point, we should either
never overwrite (not even same lemming), or first cut that lemming's future and then insert (what I suggest).
I agree that it's odd to allow overwrite same lemming, but keep the lemming's future.
In 2022/2023, I've played Lix with insert mode always-on, as a playtest. The first result (https://www.lemmingsforums.net/index.php?msg=97551) was that same-lix-overwriting sucks when you preserve the same lix's future.
Quote from: namida on January 23, 2025, 08:37:46 PMiffy about the idea of erasing all future assignments for the same reasons. Additionally, it might be useful for the player to refer to the future assignments when correcting them
This is vague, what exactly are you doing? Do you look at the listing (as if you loaded the replay in a text editor) to see what the original replay was? When I fix a replay, I know enough of the solution, I've never needed a mixed list of old and new assignments.
Or do you need this when you move assignments by only a few ticks earlier/later? You have a chance then that the old assignments stay meaningful.
Quote from: WillLem on January 30, 2025, 04:11:02 PMYes, because the player is in Replay insert mode, which never allows overwriting:
reinforcing the player's choice to be in Replay Insert mode
This is backwards. It's okay to look at what the existing mode does (to not confuse existing users), but it's irrelevant what either of us supposes for the existing mode's design.
In your design, there are two modes: Always cut, or never overwrite. If your never-overwriting mode comes closer than always-cutting to what the player really wants/needs, he chooses to use never-overwrite mode (regardless of any design ideas behind that mode) and can still be unhappy.
Indeed, the natural next idea is to consider three modes.
Quote from: WillLem on January 30, 2025, 04:11:02 PM1) hotkey to allow overwriting
accept that this will also allow overwriting to a different lemming
Quote from: WillLem on January 30, 2025, 04:11:02 PM3) third mode:
preserves everything it can, but does allow overwriting
accepts the potential for accidental overwrites
Here's how these will behave in practice:
- Lemming becomes builder at tick 100.
- We want to assign him basher at tick 100.
- We go to the always-preserving insert mode because that protects against overwriting a different lemming.
- Assignment fails (because of old same-tick assignment).
- We framestep forward and back to see which lemming has the old assignment.
- Ah, it's the same lemming, therefore the overwrite is safe.
- Hold hotkey, or enter third mode (essentially the same idea).
- Assign to overwrite.
Two annoyances:
With 1) or 3), you still require the player to back-and-forth manually in step 4, to see who gets the clashing assignment. You've already identified that this is a problem, and you're looking into other solutions, I'll get to it later.
With 1) or 3), you still don't cut the lemming's future in step 8. I recommend to either forbid the overwriting, or to overwrite by cutting the same lemming's future.
Quote from: WillLem on January 30, 2025, 04:11:02 PM2) make it optional
doesn't allow on-the-fly switching
At first, this sounded like 1) or 3), but with a user option instead of a third mode during play. But I won't dissect it yet, because then you write:
QuoteIt also means figuring out the how when it comes to implementing same-frame same-lemming overwrite, which (full disclosure) isn't trivial!
This is getting to the heart of the matter.
What we really want is freedom to design the mode around clearly visible system status. You want to see ahead of time who/what exactly will be assigned, so we know what exactly will be overwritten/why the click will fail. You'll give the player the best information before he clicks at all. (You can still give feedback after the fact.)
And the important starting point is to ferry information from replay to the UI ahead of time about who will be overwritten.
I'm happy to dissect the NL code with you.
Tomorrow (Tuesday, Feb 4th), I have a day off work, and I can offer you any time of the day for a Mumble session. Do you have time around 18:00 UTC?
-- Simon
Quote from: Simon on February 03, 2025, 03:52:58 PM... or by cutting the same lix's future.
The current CE Replay Editor has this functionality:
Choose an assignment, click "select all future assignments for this lemming", then delete.
With that being the case, do you still insist that Replay Insert should allow overwriting to same-frame-same-lemming?
Erasing future assignments invisibly seems way too aggressive. I have to agree that it solves the problem of those assignments not being in correct sync, but I'm still not entirely convinced we should be overwriting assignments at all, let alone deleting all of a lemming's future assignments
as well.
Consider a player accidentally deleting 20 carefully configured future assignments with a single click; we should guard against this, however unlikely it may seem. Held hotkey solves this.
Quote from: Simon on February 03, 2025, 03:52:58 PMI'm happy to dissect the NL code with you.
Tomorrow (Tuesday, Feb 4th), I have a day off work, and I can offer you any time of the day for a Mumble session. Do you have time around 18:00 UTC?
Yes, that would be great. Let's do it.
Not knowing the "how" shouldn't be a factor. Let's figure it out and then we can decide what we want to do with fewer limits.
All right, Tuesday (today) at 18:00 UTC. See you!
-- Simon
WillLem and I know where to attack in the source, but source discussion has a separate topic. (https://www.lemmingsforums.net/index.php?msg=105560)
Back to the design of insert mode.
Will uses NL's insert mode often, or rather the SLX mode that is NL's mode with absolute overwrite prevention. For this post, I'll define it as:
- In cut mode, on new assignment, cut all lemmings' future, then add the new assignment.
- In insert mode, on new assignment, look at the next physics update; if no assignment sits there, add the new assignment. (Never remove or overwrite.)
- Air clicks cut all lemmings' future only if you're in cut mode.
For reference, Lix's insert mode:
- In cut mode, on new assignment, cut all lix' future, then add the new assignment.
- In insert mode, on new assignment, cut the same lix's future, then add the new assignment.
- Air clicks cut all lix's future regardless of mode.
Will cares about integrity of the replay as a whole. This guarantees that you can revert your change. Any map click in insert mode either does nothing, or it inserts exactly one assignment, which you can revert by erasing.
I care about integrity of unaffected timelines. When lemmings A and B will not interact, assignments to A in insert mode should not affect what B will do. This is weaker than Will's goal of preserving the entire replay. I welcome cutting A's future because junk assignments are annoying. I accept that this has no easy reversal.
QuoteConsider a player accidentally deleting 20 carefully configured future assignments with a single click; we should guard against this, however unlikely it may seem.
For air clicks, I haven't made up my mind about how much value the easy reversal has. In today's stream of NepsterLix, I played Lots of Small Tasks, a 20-fold disjoint union. I was in insert mode throughout. I took care not to click air by accident. I explicitly say so in my twitch stream at 57:50 (https://www.twitch.tv/videos/2376855726?t=0h57m50s) -- this is again the lingering fear that I'd like to design away.
On the other hand, when air clicks in Lix's insert mode didn't cut the global future, I got annoyed in 2022/2023.
When I'm sure that my click goes to the desired lix, I haven't experienced such fear recently. I suppose that misassigning to wrong lemming, and accidentally cutting his 20 assignments, is rare enough. But I can't prove that either.
In Lix, sometimes, I cut the same lix's future explicitly. Maybe I do this when I really care about the replay as a whole? I haven't paid attention to that yet. Sometimes I'll implicitly cut by assignment in insert mode. One big idea behind Lix's insert mode is that I wanted to solve disjoint unions and have each sublevel feel like it has its own replay.
I have no good answer for the design yet. A complete undo stack of replay changes feels like travelling in a new fifth dimension (x, y, physics updates, replay, undo), but it's not out of the question. I'll sleep over it more.
-- Simon
Quote from: Simon on February 10, 2025, 01:13:55 AMWill cares about integrity of the replay as a whole ... I care about integrity of unaffected timelines
There are definitely benefits to both designs. One preserves everything indiscriminately and protects against accidental clicks/assignments/etc, the other allows replay tweaking on-the-fly rather than having to open a separate replay editing window.
As with most things, it comes down to user preference. Personally, I'm likely to continue to want Replay Insert to be a total "No Overwrite" mode for my own purposes and so this will probably continue to be available (if not default) behaviour, but I would be open to adding an option, a hotkey, or some other way of getting the Lix-style behaviour if people want it, and if we can figure out how to do it!
Quote from: Simon on February 10, 2025, 01:13:55 AMI played Lots of Small Tasks, a 20-fold disjoint union. I was in insert mode throughout. I took care not to click air by accident. I explicitly say so in my twitch stream at 57:50 (https://www.twitch.tv/videos/2376855726?t=0h57m50s) -- this is again the lingering fear that I'd like to design away.
On the other hand, when air clicks in Lix's insert mode didn't cut the global future, I got annoyed in 2022/2023.
The proposed (and, let's be clear, current) NL-CE behaviour solves the first problem and creates the second. It seems there is no easy answer for "should clicking air cancel Replay Insert?" - I'd lean more towards that it shouldn't, for similar reasons to not wanting to overwrite assignments.
Then put absolute overwrite prevention into the next release. It's already better than NL 12.14, which accidentally overwrites different lemming.
The problem with your hotkey remains that it overwrites different lemming, which nobody wants. We have seen that different-lemming prevention is amenable code-wise. I'll help you until it's done.
-- Simon
Quote from: Simon on February 10, 2025, 10:54:43 PMThen put absolute overwrite prevention into the next release.
It should already be in the RC...? (Can't check right now, on mobile).
Quote from: Simon on February 10, 2025, 10:54:43 PMThe problem with your hotkey remains that it overwrites different lemming, which nobody wants.
It doesn't have to. If we figure out SameFrameSamLem, that could be the hotkey behaviour for sure.
Quote from: Simon on February 10, 2025, 10:54:43 PMI'll help you until it's done.
That's good, I appreciate that. You help temper some of my more haphazard coding habits and it's always nice to have your company :)
Quote from: WillLem on February 11, 2025, 01:42:52 AMQuote from: Simon on February 10, 2025, 10:54:43 PMabsolute overwrite prevention into the next release.
It should already be in the RC...?
Ah, yes, RC1 prevents all overwrites. It behaves as follows. Situation:
- Replay contains old assignment for the next tick.
- Activate insert mode.
- Point to a lemming that would normally (= if nothing were in the replay) eligible to be assigned.
- Click.
The game then does:
- You hear an assign sound.
- The replay stays as before the click. You didn't cut, you didn't insert.
- Physics advance once.
- The old assignment replays.
This UX is problematic. You hear the expected assignment sound exactly as after a successful click, and the physics advance, too. But the click didn't produce what we wanted. It feels like a bug.
It's outright misleading when we assign permanents that will do nothing on the immediate next frame. The potential assignee does exactly what he would do if the click's assignment went through: Walk forward once.
-- Simon
Quote from: Simon on February 12, 2025, 06:31:39 PMThis UX is problematic. You hear the expected assignment sound exactly as after a successful click ... It feels like a bug.
The assignment sound happens because of the original assignment, this we know. You should
also hear the assign fail sound as well; can you confirm this?
But yes, it's clearly not ideal.
My suggested solution to this if we keep "no overwrite" behaviour would be to only trigger the assign fail sound for this particular situation (i.e. attempted assignment fails due to existing assignment). The slight inconsistency with the fact that the assignment sound is heard wherever else there is assignment during replay mode is acceptable; here, the assignment failure feedback is more important.
Yes, I hear both the successful old assignment and the short click for the failed assignment. I didn't notice that yesterday.
I agree that you shouldn't play a successful sound here.
On a click that will not assign, don't advance physics in the first place? Play only the failed assignment. Then you won't have to introduce inconsistencies. On air clicks, you probably want to advance physics, but air clicks are safe, can't mistake air clicks for a wanted assignment.
Wondering if you want to tell people before the click that the assignment will not go through.
-- Simon
Quote from: Simon on February 13, 2025, 02:38:10 AMI agree that you shouldn't play a successful sound here.
OK, I'll implement this for the 1.0 release version.
EDIT - This is now implemented ready for release.Quote from: Simon on February 13, 2025, 02:38:10 AMOn a click that will not assign, don't advance physics in the first place? Play only the failed assignment. Then you won't have to introduce inconsistencies.
Unless I'm misunderstanding what you mean, not advancing physics on a mouse click
would be inconsistent. At every other time, clicking advances physics; I see no reason to change this.
Also, the player needs to see the reason their assignment has failed: because there is an existing assignment, which will be activated on clicking and advancing physics.
(Again, I might have misunderstood what you meant).
Quote from: Simon on February 13, 2025, 02:38:10 AMWondering if you want to tell people before the click that the assignment will not go through.
We'd need a way to detect future assignments to the selected lemming, which we currently don't have (but would likely need to be implemented to allow same-frame-same-lem assignments anyway).
What sort of feedback do you imagine? Some ideas: the lemming could simply not be selectable on the frame prior to the assignment, or the selection rectangle could have a big "X" through it. A "this lem cannot be assigned" message in the panel would also be OK.
This could look like a bug, though. I still think the failed assignment itself is enough feedback: let the user know
why it's failed, rather than that it can't happen (but without providing a reason).
Consider: the user cannot assign on the next frame anyway, so physics might as well advance, the fail sound plays, the original assignment is seen, and the player can see the reason why they can't assign on that frame. They then simply step to another frame to assign the new skill or use the Replay Editor to remove the original assignment if it absolutely must be on that frame.
Quoteinconsistent
might have misunderstood
I meant: In NL 12.14, all replayed assignments sound the same (all play the regular assignment sound effect). In your RC2, only some replayed assignments will sound like that. Those replayed after a failed click will produce no sound. This will be less consistent.
But it's decent. It's better than (advance physics + play sound for successful assignment).
Next week, I will playtest in Lix: Replayed assignments sound different than freshly clicked assignments.
Quotenot advancing physics on a mouse click would be inconsistent.
The intuition here was: If you can't give the player what he wants the most (assignment), give nothing. Don't give 30 %. Fail as clearly as you can.
The alternative to make all click failures not advance physics. E.g., player clicks to assign basher to basher, physics shouldn't advance. Then that not-advancing will be consistent with the not-advancing on failures that come from old assignments in the replay. You'll also preserve the sound consistency; all replayed assignments produce the same sound.
Quoteuser cannot assign on the next frame anyway, so physics might as well advance
Hmm.
He can change the release rate, but that would be a feeble argument.
He can delete the old same-lemming assignment, then assign. If you advance, he'll have to rewind, then delete, then assign. I'll sleep over this.
Quotelet the user know why it's failed
physics might as well advance
original assignment is seen
The original assignment can be elsewhere in the level, for an unrelated lemming.
This will remain a design problem even if you eventually allow same-lemming overwrite as an option. I have no good answer for this.
QuoteWhat sort of feedback do you imagine?
No idea yet. This design problem is entirely new. I was curios how satisfied you were with the RC's feedback on failed clicks. Yes, assume that we solve all technical problems, e.g., how to fetch this information from the replay.
I agree that we shouldn't make things look like bugs. Generic crossed-out cursors or no-signs won't clarify the reason behind the click that is going fail. Some leeway you have, it's a corner case in an expert feature.
If you're happy with what you have, release CE 1.0 with what you have. It's better than NL 12.14 because it prevents accidental different-lemming overwrites. We can solve the hard design problems in March. And user options for same-lemming overwriting (really: cut future of that lemming, then assign) can also wait.
I don't mind going 5 times in circles with this. You're the first to shred the Lix design choices. I wonder if I want to make it a user option in Lix whether air clicks in insert mode cut the replay.
-- Simon
Quote from: Simon on February 14, 2025, 01:49:52 AMIn NL 12.14, all replayed assignments sound the same (all play the regular assignment sound effect). In your RC2, only some replayed assignments will sound like that. Those replayed after a failed click will produce no sound. This will be less consistent.
Yes, having implemented this and tested it a few times, it does feel somewhat odd, even if it is technically "better UX"...
Quote from: Simon on February 14, 2025, 01:49:52 AMThe intuition here was: If you can't give the player what he wants the most (assignment), give nothing. Don't give 30 %. Fail as clearly as you can.
...
Then that not-advancing will be consistent with the not-advancing on failures that come from old assignments in the replay. You'll also preserve the sound consistency; all replayed assignments produce the same sound.
I see. In that case, this is definitely worth a try.
For RC2 For the 1.0 release*, all assignments that fail due to an existing assignment at the same frame don't advance physics (and, trigger the Assign Fail sound as feedback).
*RC1 feedback has been slow, let's just go ahead with the release version. We can always tweak this again in later updates.
Quote from: WillLem on February 15, 2025, 11:45:23 PMassignments that fail due to an existing assignment at the same frame don't advance physics
... but all other failures to assign still advance physics: You select basher, you click on a basher, and physics advance from this failed assignment.
I agree that this combination a good choice to try in public. I'm not sure if it's absolutely best and I'd like to see feedback.
Reason: I've experimented with non-advancing failed assignment in Lix singleplayer streams. It wasn't fun to block
all failed assignments from advancing physics. When an ascender/hoister is still ascending, but we know that he'll be assignable within 1-3 physics updates, I'll select builder and click on him several times. This ensures that he builds ASAP. I didn't know that I used this pattern until I removed it experimentally, and I'm putting it back in. :lix-grin:
-- Simon
Quote from: Simon on February 22, 2025, 04:25:38 PMWhen an ascender/hoister is still ascending, but we know that he'll be assignable within 1-3 physics updates, I'll select builder and click on him several times. This ensures that he builds ASAP. I didn't know that I used this pattern until I removed it experimentally, and I'm putting it back in. :lix-grin:
Yeah, exactly. This is one of the reasons I wasn't sure about preventing physics advancements. I'm still not 100% sure it's best either.
It works well to offset confusion caused by either "we heard the assign skill sound but this is not the skill we tried to assign" or "we heard the assign fail sound and yet the lemming has begun an action", but also causes the player to have to click more times to get to a frame they can assign upon. If we advance physics and allow the sound clashes, we get to assign in fewer clicks.
There is probably no 100% correct answer to this one. Happy to consider any ideas that anybody might have.