WIP: proposal for ABI version generation#1933
WIP: proposal for ABI version generation#1933illwieckz wants to merge 1 commit intofor-0.56.0/syncfrom
Conversation
| } | ||
|
|
||
| info_map["gamename"] = GAMENAME_STRING; // Arnout: to be able to filter out Quake servers | ||
| info_map["abi"] = IPC::SYSCALL_ABI_VERSION; |
There was a problem hiding this comment.
This couldn't work because the game was comparing abi with IPC::SYSCALL_ABI_VERSION to check if that was different, but it was the same.
There was a problem hiding this comment.
What do you mean it was the same?
There was a problem hiding this comment.
On game side it was doing:
if ( Q_stricmp( rocketInfo.data.servers[netSrc]->abiVersion.c_str(), IPC::SYSCALL_ABI_VERSION ) )
Though there was two mistakes making abiVersion an empty string there, but once those two mistakes were fixed (info string being named abi and not abiVersion, and the right pointer being used), the game code intended to compare info_map["abi"] with IPC::SYSCALL_ABI_VERSION.
The comparison would always have been true when comparing a game built on 0.55 and a game built on 0.55 + incompatible things.
There was a problem hiding this comment.
The comparison would always have been true when comparing a game built on 0.55 and a game built on 0.55 + incompatible things.
Wat
I literally have screenshots in the original pr that added the check that disprove this.
There was a problem hiding this comment.
Here I'm talking about the current code from for-0.56.0/sync here. The one we can test with the RC2 build and test server.
I'm not saying it may have not worked in the past, but the code in the RC doesn't work. I have not investigated when it broke and how. I wouldn't exclude some mistake may have slipped in, I don't know.
This branch focuses on fixing what is currently in for-0.45.0/sync.
There was a problem hiding this comment.
I wouldn't exclude some mistake may have slipped in, I don't know.
One might say sliphered in
There was a problem hiding this comment.
As I said I have not spent time to git blame the code, I focused on making it work, starting from what I had in hands.
Sometime I spend a lot of time investigating things and tracing code from history, like in this comment where I traced code 20 years back.
The release is now expected to happen very soon, so I'm ironing the last bits and so right now I focus more on that polishing effort itself than knowing why it is broken.
| info_map["abi"] = IPC::SYSCALL_ABI_VERSION; | ||
| // Add the engine version. But is that really what we want? Probably the gamelogic version would | ||
| // be more interesting to players. Oh well, it's what's available for now. | ||
| info_map["daemonver"] = ENGINE_VERSION; |
There was a problem hiding this comment.
This is removed for now.
| static Cvar::Cvar<std::string> abiVersionCvar( | ||
| "version.daemon.abi", "Virtual machine IPC ABI version", Cvar::SERVERINFO | Cvar::ROM, | ||
| std::string(IPC::SYSCALL_ABI_VERSION) + | ||
| (IPC::DAEMON_HAS_COMPATIBILITY_BREAKING_SYSCALL_CHANGES ? "+compatbreak" : "")); |
There was a problem hiding this comment.
It was the only place where that string was constructed, but it was needed in more places. It was actually the only place where using that custom string did nothing.
|
The check is only done on the abi version string. The game code currently uses the abi version string as displayed version. Displaying engine and/or game version would require more work because we better store the game and engine version in the status string instead of the info string. The info string sould be kept as short and unmodified as possible for various reasons:
For example in our server browser, we may only display what is currently displayed with this branch, but when clicking a server, display map levelshot, player names, engine version, mod name, mode version, etc. Many stuff meant to be in status string. The status string is basically the custom game-specific protocol, while the info string is a somewhat standard protocol like HTTP: one doesn't modify HTTP to tweak his web page. Some minor changes being done to the info string can be accepted if it is really worth it, like the way we disclose the amount of bots (non-standard), and the api (non-standard), because it makes easy and fast to build a server list without querying and parsing the status string that can be much much longer. |
|
It should be noted that the As a side note, I do believe it would be better if it was named |
It doesn't.
It is. Are you just removing random shit now? |
I'm stating what the code does in that branch. Here “current” qualifies the code in that branch, not the code before the change.
Can you show me where?
Higher-quality relationships will help us build a more peaceful partnership. 😉️ |
| std::string AbiVersion() | ||
| { | ||
| return std::string(IPC::SYSCALL_ABI_VERSION) | ||
| + (IPC::DAEMON_HAS_COMPATIBILITY_BREAKING_SYSCALL_CHANGES ? "+compatbreak" : ""); |
There was a problem hiding this comment.
Why cannot we simply increase the ABI version when something breaks compatibility?
There was a problem hiding this comment.
This is exactly what we do.
Once 0.55.0 is released, the ABI version is increased to 0.55.
Once breaking the ABI we create a “future” branch named for-0.56.0 and we increase the ABI version to 0.55+compatbreak.
Once we are releasing 0.56.0, the ABI changes are then considered stabilized for the 0.56 cycle and we increase the ABI version to 0.56.
This change makes that ABI version bump more obvious and easier to deal with, by providing a function that returns the current ABI version, bumping it for us when needed.
There was a problem hiding this comment.
Instead of modifying by hand the 0.55 string to 0.55+compatbreak, we just turn one boolean to true to tell a breaking change is on the go. Unlike a string, the boolean is typed and the compiler will catch possible typos, and the base version string is left untouched, preventing typos as well.
Then this function generates the ABI version string for us.
When releasing the game, we run a script. That script bumps the ABI base version string from 0.55 to 0.56 for us, and reset the “work in progress” boolean to false for us, automatically.
There was a problem hiding this comment.
This is the opposite of "easy to deal with". No innocent looking function like this should ever return anything but the true ABI version. You should at least rename this function to something that induces the necessary caution in the reader, like HairyAbiVersion.
If you want to change the ABI version in a development branch, give it an actual version string.
There was a problem hiding this comment.
Unlike a string, the boolean is typed and the compiler will catch possible typos, and the base version string is left untouched, preventing typos as well.
Requiring a type system to type a version string is, of course, utter derangement. If someone is unable to write a version string, then they should not change it.
There was a problem hiding this comment.
This thread doesn't discuss what real men would do.
Right now the code used in the release candidate would make the in-game server browser wrongly report all game servers as incompatible servers. It would be very bad to release a new version of the game with such a serious bug. This branch is about fixing that bug and we're discussing the implementation of that fix. We're not discussing the feature itself that is fixed.
If you still want one word from me about the feature itself that is fixed, the ABI version string generation is part of an effort to automatize even more the release process to reduce the manpower required to release the game. The version bump is meant to be scripted. From this point of view, the fact that someone is able or not to write a string is out of topic, as the purpose is to require less work from the man to begin with and delegate that work to the machine. That's all I have to say on the topic of ABI version string generation itself.
I know you are well aware of the small bus factor of the project and other manpower shortcoming we struggle with, so I will not spend more time on discussions that would only have effect to put more work on the shoulders of people. I do believe we will agree giving people more work to do is not the way to go if we want to reduce the amount of work required to release things.
There was a problem hiding this comment.
This thread doesn't discuss what real men would do.
Your sarcasm is inappropriate.
You are proposing confusing semantics for something that should be most simple: a version tag. The only goal I could identify so far is that you need this for some code-generating script you are using. That does not seem to justify the addition of technical debt to the code base.
This is even more so during the late phase in the release process. You agreed to a freeze.
I know you are well aware of the small bus factor of the project and other manpower shortcoming we struggle with, so I will not spend more time on discussions that would only have effect to put more work on the shoulders of people.
There are several 0.56 test servers online, I host one of them. Do you have any problems with my server?
There was a problem hiding this comment.
I'm not proposing that version string + boolean thing. This design predates my PR.
I'm not the one who designed that version string + boolean thing.
You're blaming me for something I haven't designed.
You're blaming me for something I'm dealing with.
You're blaming me for something I explain to you.
I'm fine with many designs and solutions. Here I propose one solution around the design we currently have. I explain to you the situation I'm dealing with. Stop blaming me for random things I'm not even in fault at.
There are several 0.56 test servers online, I host one of them. Do you have any problems with my server?
Why are you turning it personal? This has nothing to do with your server itself or any effort people would put into their server. I have nothing with your server and you know it.
Just do the test, run the RC2 build, and open the in-game server browser, you'll see that all entries are listed with an empty version string. An empty version string is not equal to the engine version string, so all servers are considered incompatible, and if we release the game with this bug all servers will be wrongly considered incompatible. This includes any server, including yours. If we don't fix the bug, the game will wrongly discourage people to join servers, including your server, wrongly believing the server is incompatible while it will not be.
If you don't want the 0.56.0 release to ship with a bug so serious it would discourage people to play the game and to even play your own server, stop hindering the resolution of this bug.
At this point the bug is so serious that any fix, be it ugly or suboptimal, has to be done. Even an ugly workaround hack would be better than shipping the bug.
At this point we should not mind if the solution is clean or not, if the design we're dealing with is clean or not. Priority is to fix the bug before the release. Discussing a better design can even be postponed to after the release if we can make the release unbuggy with whatever solution we have, and it's OK to do that.
This is a classic “important versus urgent” thing.
Doing a better design is important, fixing the bug is urgent. Classifying and planning things among important and urgent things is part of very first lessons in ITIL training.
Let's quote that first sentence from that Wikipedia page on ITIL:
ITIL (previously and also known as Information Technology Infrastructure Library) is a framework with a set of practices (previously processes) for IT activities such as IT service management (ITSM) and IT asset management (ITAM) that focus on aligning IT services with the needs of the business.
Here the needs of the business (that means our needs and your needs) is to get the release not discouraging players to connect servers including yours because of a bug wrongly reporting a server incompatibility.
Right now I'm working on aligning the IT service (the dæmon engine and the game code) with the needs of the business (you getting players joining your servers). Good practices in such situation is to classify urgent and important thing. Fixing the bug is urgent, redesigning the infrastructure is important. I'm fixing the bug first to satisfy the customers (which here are both players and server owners like you), and I'm OK to postpone any discussion on the redesign to be done after the customer is satisfied, so we can prepare more future satisfaction in a better way.
This is project management 101.
I assume you have the expectation that the engine and gamecode doesn't wrongly discourage players to join your server because of a bug, so I'm working on making sure the engine and gamecode meets that expectation.
This is me putting your satisfaction first. Please stop hindering me putting your satisfaction first, please stop hindering me making sure I deliver you what your satisfaction requires.
There was a problem hiding this comment.
When I say “This thread doesn't discuss what real men would do“, I emphasize on the fact this thread is not about discussing a better design, but about fixing a bug before a release to meet a dead line.
Discussing what real men would do can be fine, but it's an important thing.
Fixing the bug and delivering is the urgent thing, this thread is about fixing the bug and delivering, not about designing.
I'm not saying we cannot discuss what real men would do, I'm just saying this is not the topic of this thread and that such topic, if it should happen, may be postponed to meet the dead line.
Okay that's definitely a confusing meaning to assume for the word "current".
In the cgame code that checks abi version against |
|
The The The code in We would not need to set the ABI version in the The simple fact the code works when parsing the |
Okay, it uses abi version string without that random extra crap that's in the cvar. Which changes nothing because it's still the abi version and is the correct thing to check against. |
|
Before creating the pull request my testing process for that change have been this one:
|
It is good enough when attempting to run 0.55 on 0.56, it wasn't featureful enough for the use case of running 0.55 on 0.55+compatbreak. I should have mentioned it in first post (my bad), but this branch doesn't just fix the bug that is currently in The bug of the version string being displayed as empty in 0.56 RC2 is a two-line fix ( This patch does more than two lines because it also makes sure the server list reports the server is on |
|
The ABI version in If the ABI in the Using This branch not only fixes the ABI mismatch detection between major engine versions (which was just a field name mistake), this branch extends that detection to work-in-progress engine builds as well, including release candidates. |
|
So get rid of the stupid hairy compat-whatever bool and some hidden script that randomly changes code, and change abi version string at the start of a compat-breaking branch like a normal software project. I do not get the insistence on stacking more and more layers of shitty abstractions for a simple thing. |
Stop with the creative versions, what are you doing? Change version string in for-0.56.0 to |
|
I focus on fixing the shortcomings seen in the release candidates to make the release happen. |
|
Lack of a complex abstraction with no clear benefit is not a shortcoming. |
|
Getting rid of the bool seems like a good idea, given that it is causing some issues. When starting a for-X.Y.Z branch, instead of changing the compat-break bool from false to true, we could just change the ABI string from |
|
Maybe it would be nicer to call the ABI version |
In discussion of DaemonEngine#1933 it has been observed that this causes issues with the version check when using the server list on an unstable branch, and that the bool is unnecessary complexity. Instead of having the bool we can just add something in the version string to indicate the unstable ABI. The only thing lost by removing DAEMON_HAS_COMPATIBILITY_BREAKING_SYSCALL_CHANGES is the log message advising that the unstable ABI branch is being used.
I meant that complex abstraction or not, I'm right now focusing on things affecting users (players) directly. If we take anything from the underlying technology that can be done better as valid candidates for spending resources on at the risk of delaying the release, we will never release. I'm not responding about the validity of the concern neither the seriousness of the matter, I'm responding about planning and resource management. My answer there is about project direction, not problem solving. |
That will work too. My approach when doing this PR was to be conservative towards what we had.
A log unconditionally printing the ABI string whatever that string is may fit the need. |
|
I am still confused about this PR. Is there really anything to fix? Of the three 0.56 test servers currently online, two seem to work just fine. The third one is yours. Perhaps I did not understand the problem in detail. Can you explain it? |
I do not need to follow all your development branches to identify and reject code that introduces technical debt. What did you do that broke this in the first place? It does not happen with the gamelogic branch I am using. Which branch are you using? |
|
For reference, I should add a link to Unvanquished/Unvanquished#3469 By your own schedule, there are only two days left until you update clients. Once you publish a schedule, people start to plan their own activities accordingly. I am one of these people, and there are several others. It is too late to make compatibility breaking changes. |
|
From your own patch listed above, quote: + const char* version = Info_ValueForKey( info.c_str(), "version" );
+ const char* abiVersion = Info_ValueForKey( info.c_str(), "abiVersion" );
+
+ if ( !*version ) {
+ version = Info_ValueForKey( info.c_str(), "daemonver" );
+ }
+
+ if ( !*abiVersion ) {
+ abiVersion = Info_ValueForKey( info.c_str(), "abi" );
+ }You literally implemented a fallback for an implementation that should be removed, and the working fallback is implementing my own patch from that comment that was the first version of that branch:
and that slipher reimplemented there: This very change of mine you had to do to make it work on you side is even still present in my own PR: So, who are you trying to fool? Your screenshot only works because you imported part of my fixes ! As said in earlier comments, added to that fix I wrote and that you imported, I proposed a reword of an existing version string construction mechanism (that existed before I touched that code) to be reusable. This changes no ABI. This is not compatibility-breaking change, this is a fix for a bug in a compatibility-breaking bug. Who are you trying to fool, really?
Yes, because the subset of the patch I wrote that you imported was especially meant to not change the |
I am not trying to fool anyone. I am proving that your last-minute changes to the engine are not needed. They should be rejected. |
|
Out of curiosity: which part of your code are you claiming that I am using here? |
You do not need to follow anything. But also: You have no duty to identify anything and you have no duty to reject anything. I have to remind you that around March 20th of 2025 (one year ago in two days),
You also stopped contributing. Before that, you were contributing to gameplay (which was good) but weren't an engine developer. As far as I know your only two commits on engine (which I am grateful for) were those twos: Those commits were unrelated to topics you now pretend having an expertise on.
Not only this doesn't make compatibility breaking change and this is a fix for a compatibility breaking, but also this is done in a branch that was never released, so even if that was breaking compatibility, no one would care because it would only break something with something unreleased. Seriously, you're not only wasting my time, you're wasting yours.
This PR was written around features I didn't wrote, to fix a bug I didn't introduced.
I do remind this PR is a proposal, there are ways to do it in a more succinct way like: Which is actually the first version of my branch before I squashed the “reword the existing version string generation” stuff that happens to extends detection to intermediary branches at the same time. You'll notice I never insisted for this branch to be merged over the more succinct way that is: And that more succinct way is based on my own instructions. This PR is a proposal. It has not been merged. |
|
There is no need to get personal. Your code should be rejected for objective reasons.
I did. To protest against your very questionable leadership that is tearing this project down.
I did not.
You made sure that nobody protesting in that way will ever be allowed to contribute again. How could I contribute again?
I do not know what it means to be an engine developer. Your code is bad, it should be rejected.
Like doing nothing at all. Which is clearly the better choice. |
No, but once this piece of homework has been self-marked, it will be. I'm confused as to what the issue here is, and why all of this is needed. What is this fixing? Neither of the issues here are explaining why this change is proposed. |
I'm not saying you're using my “code” as it you copy-pasted the exact wording of any commit I did. What happens is that I told here that:
So basically, I told that the fix (given here in sed substitution syntax) is to rename “abiVersion” to “abi” on the client side code. This is what your patch does: + const char* version = Info_ValueForKey( info.c_str(), "version" );
+ const char* abiVersion = Info_ValueForKey( info.c_str(), "abiVersion" );
+
+ if ( !*version ) {
+ version = Info_ValueForKey( info.c_str(), "daemonver" );
+ }
+
+ if ( !*abiVersion ) {
+ abiVersion = Info_ValueForKey( info.c_str(), "abi" );
+ }So yes, your patch shows a code that is checking for the “abi” key instead of the “abiVersion” one. This is semantically and functionally the same, despite language and implementation differs. So yes, the only reason why your screenshot displays things correctly is because the code your run is using a patch that implements the exact same fix, in your own way, than the one I implement and submitted for review. Also, actually I even don't mind if someone would have implemented such fix before anyone else, I'm not discussing paternity. What I'm discussing is identity. You shown a screenshot that requires the exact same fix as mine to be done first, and you pasted a patch that implements the exact same fix. But also you said:
I didn't broke it, and the gamelogic branch you are using is implementing the same kind of fix I suggest. Also, as I already said, I also proposed some more reword around that fix, that's all. You're just making a lot of noise for nothing. |
It is not my own patch, as you would know if you had not excluded me from contributing branches for life. This particular change was made by another contributor a few months ago. But let us stop here. I claimed that no change to the engine is required, and this has been proven correct. You shall not change the engine code to be released on sunday. |
@cu-kai The issue to fix is: The fix is: Around that fix I also proposed a small rework that, based on the existing design that I'm not the original author of, also makes the existing feature work with work-in-progress branches. That's all. Given that small rework is small and would better be in a A very simple answer could have been for example: “Maybe we better just rename the strings right now, and postpone the rest to after the release.” Or something like that, that would have been perfectly fine. |
If that is the case, why are you still pushing for last-minute engine changes? You are the person in control of the updater. You should not behave like this. A freeze is a freeze, except for critical problems. This is not a critical problem.
No. It is frozen by your own decision.
Who knows what is right and what is wrong? But the code is frozen. You shall not change it. |
Honestly, the behaviour in itself is not very clear. I assumed this was how it was supposed to work because the versions were incompatible. I don't like the That is for another issue or PR though. This feels like yak shaving. |
@sweet235 It is true and it is fine, you should have started with that. You're only saying that now because I, argument per argument, shown that what you were saying were out of topic or wrong, until that you finally started to grasp the topic thanks to all my explanations. Then, only, then, you could say that. I don't blame you for not knowing what this topic is about you, but I can blame you for interfering with discussions before you know the topic the discussion is about.
As I said, I even don't mind who's author is, the important bit is that your code uses the exact same fix of mine. If that fix isn't in the release, we should implement it, whatever patch you have or not on your side.
This is not true, I never excluded you from contributing, and you are not excluding from contributing branches. You can submit a PR anytime, which requires you to submit a branch, for example a branch from your own GitHub fork using the GitHub mechanism, something you can do. You decided to leave the team and remove your push permission from upstream. This is your decisions, not mine. Even those decisions of yours doesn't prevent you to contributing and contributing branches. Myself haven't done anything to prevent you to contributing.
If you had this patch on hand since months, why did you not have submitted it? You have full permission to submit such patch. |
It is a ruse, don't fall for it. The argument presented for this PR claims that an engine change is required. But that is not the case. |
Yes, that's not very clear, but then I spent hours to track it down, even capturing UDP frames with wireshark to check my assumptions for being correct.
That's the kind of discussion we can have, but that doesn't prevent to implement the fix.
Yes. I even did not change that.
This whole drama is yak shaving, indeed. |
@sweet235 What? No engine change is required. This engine change is only proposed because I thought it was even better this way. People can disagree on that, it's fine. A ruse for what? Can you fully describe your conspiracy theory? |
You can blame me for whatever you want, that means nothing. However, your very PR attempts to change the engine code to be released in two days. If you do that, this will be on you.
It really is not. I may protest however I choose. If that makes you so angry that you decide that I will never again be allowed to push branches again, then you lost an contributor. That is your choice, not mine. Please restore my writing permissions.
I am glad you see this now. Close the PR. |
@sweet235 You are allowed to submit branches. You're the one who decided to renounce your permission to push branches upstream. I never did nothing to prevent you to contribute. |
That is off-topic. Will you close this PR or not? |
|
The simple fix is now merged: This is turned to draft as the simple fix doesn't need it and this can be discussed after the release. It's possible this becomes obsolete if we change the underlying design this change is written against: |
@sweet235 This PR may or may not be closed, we'll see. There is a very high chance this PR gets closed at some point. I do believe it's the most probable outcome if we go the route of removing the boolean. This PR only existed because I tried to keep the existing design that had that boolean (a design I worked with, not that I am the author of). If that boolean goes away, this PR would have no sense. Despite all the noisy comments, I'm glad we could have discussed the various solutions and concerns, and even discussed the underlying design. But it could have been done in a friendlier way, and some of those discussions could have been postponed for after the release. There are many other topics related to this one, like the possible usage of version strings from the status packet instead of the info packet. If we change that other part of the current design, then this could also make this PR obsolete in other ways. I actually investigated fetching versions in the status packet in temporary work-in-progress branches for this PR, until I discovered this became too big for a small change right before release, that's why I didn't submitted it and went this simpler way. Though people may consider it wasn't simple enough, fine. |
|
Marking this abomination as WIP is good. Closing it is even better. You are expected to improve this project, not damage it. |
|
You are not in position to expect anything from me. Such expectations being good or bad expectations doesn't change that fact. You are not in position to expect anything from me.
|
It does, as long as it's present in the infostring. |
|
Yes, when listing older engines it would show |
|
I do believe it's important to notice that what happened there should not happen again. I'll just focus on some of the last words that have been exchanged. What can be said from them applies to more. To put in perspective the word “abomination” that was just used, it had been used to qualify that 4-line patch to move around some already-existing code to make it reusable in order to make both the diff a/src/common/IPC/Primitives.cpp b/src/common/IPC/Primitives.cpp
@@ -590,4 +590,10 @@ SharedMemory SharedMemory::Create(size_t size)
}
#endif
+std::string AbiVersion()
+{
+ return std::string(IPC::SYSCALL_ABI_VERSION)
+ + (IPC::DAEMON_HAS_COMPATIBILITY_BREAKING_SYSCALL_CHANGES ? "+compatbreak" : "");
+}
+
} // namespace IPC
diff a/src/common/IPC/Primitives.h b/src/common/IPC/Primitives.h
@@ -155,6 +155,8 @@ namespace IPC {
size_t size;
};
+ std::string AbiVersion();
+
} // namespace IPC
namespace Util {
diff a/src/engine/framework/VirtualMachine.cpp b/src/engine/framework/VirtualMachine.cpp
@@ -60,8 +60,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
static Cvar::Cvar<std::string> abiVersionCvar(
"version.daemon.abi", "Virtual machine IPC ABI version", Cvar::SERVERINFO | Cvar::ROM,
- std::string(IPC::SYSCALL_ABI_VERSION) +
- (IPC::DAEMON_HAS_COMPATIBILITY_BREAKING_SYSCALL_CHANGES ? "+compatbreak" : ""));
+ IPC::AbiVersion());
static Cvar::Cvar<bool> workaround_naclArchitecture_arm64_disableQualification(
"workaround.linux.arm64.naclDisableQualification",
diff a/src/engine/server/sv_main.cpp b/src/engine/server/sv_main.cpp
@@ -596,7 +596,7 @@ static void SVC_Info( const netadr_t& from, const Cmd::Args& args )
}
info_map["gamename"] = GAMENAME_STRING; // Arnout: to be able to filter out Quake servers
- info_map["abi"] = IPC::SYSCALL_ABI_VERSION;
+ info_map["abi"] = IPC::AbiVersion();
// Add the engine version. But is that really what we want? Probably the gamelogic version would
// be more interesting to players. Oh well, it's what's available for now.
info_map["daemonver"] = ENGINE_VERSION;Now the relevance of the already-existing code can be discussed, but here what is qualified as “abomination” isn't that already existing code, it is that 4-line patch that moves things around to make them more reusable. Such “abomination” word cannot be appropriate in such context and is agressive. This, associated with other wording expressing that someone's condition is to be in servitude, is brutal. That should not happen. This is a hobby project to have fun. I have to remind that, this is important. |
You accepted the role of project head of your own free will. Not only me, but the whole world can expect that you do not damage this project. |
Says the person who regularly resorts to personal attacks in technical arguments. Adding a function |



Fix ABI mismatch check.
Game companion: