SteQve's No Frills Mod Standardization Page

Technical feedback to this page is included at sfeedback.html.

Mod Combining is Really, Really Hard In Almost All Cases You Care About

If your response to this isn't "Well *duh*," this little section is for you. It *is* hard. Like, *really* hard. If you're a server owner who wants us programmer types to help you mix-and-match mods, trust us when we say it's really, really hard. We want to, but it may not ever happen.

I say it's hard "in almost all cases you care about" because I'm a computer programmer and I don't want to say anything that's technically incorrect. If you want to merge a death messages mod with a motd mod it might be OK because the two are pretty different and operate on different pieces of the code. But if you want a little bit of this with a dash of that but you don't want it to interfere with that other thing, then it gets Really Really Hard. Take the motd and death messages mod for example. If you want signon/signoff messages as part of your death messages package, that's probably going to interfere with the exact same part of the code that prints out the motd.

A Lame Analogy That Upon Reflection May Not Be So Lame

Here's an extremely lame analogy to try to get you to understand what it will be like to be able to do mod combination. Perhaps it's condescending for me to say I don't want to sound condescending, but frankly I care deeply about each and every one of you who reads this, and I don't want to offend you because you might get the wrong impression of me and that would, like, really stink in my book. But enough confessions about my personality. I want to try and explain the problem in non-technical terms. So let's get back to the lame analogy.

Imagine you're at the United Nations and you're planning a party for all the delegates. Some are vegetarians, some eat meat, some eat kosher. You don't want some delegates to sit next to each other because, even though they're similar, they're really stubborn and hardnosed and always trying to one-up each other, and so they get into fights and ruin the party for everybody.

Lots of the delegates speak Esperanto, lots of them speak English. And everybody secretly thinks that it would be so much easier if everybody else would just learn their own native tongue. But Esperanto, an artificial language, is well-known to be hard to learn even though it supposedly doesn't have all the trappings of the "natural" languages. And English - well, why do the words bough, tough, though, and through all spell the same but sound completely different? And even though most delegates speak English, the German person speaks English a little differently than the Japanese person. And I'm sure the translators do their jobs well but do you believe for one second that everybody is told the *exact* same thing when somebody else speaks? I don't. Please, no hate email from U.N. translators, I'm just making a lame analogy.

So you've got all these delegates who care about different types of food who speak different languages (or minor variations of the same language) and who have personality conflicts. And it's up to YOU to get around the language problem, figure out where they should sit, and tell them. And you're going to offend SOMEONE if you tell them what to do, so they'll leave the party.

The final kicker is: everybody wants to party but because of all the different problems, nobody wants to (or has the capability to) host it.

Hey, wait a second, that's not such a lame analogy after all. The point is: someone has to invent Esperanto for Quake mods. Then everybody has to agree to speak it - precisely. The mods that are similar to each other have to figure out a way to just get along (or, they need a host to tell them what to do). And somebody's probably gonna be left out of the dinner altogether because their dietary needs just can't be met. Oh yeah, and one final thing... Would YOU want to be the host?

Forgive the Lame Analogy and let's get to the Technical Stuff

Programming Geek Alert! Do not bother reading unless you understand at least one of the words "Recursive," "garbage collection," "object-oriented," and/or "pointer." This is not to be elitist, but it's for your own good, really. It's pretty technical and downright boring with almost none of my lame attempts at humor.

Technical feedback to this page is included at sfeedback.html.

I'm tossing my random thoughts on mod standardization into the ring. I have some ideas, but they're ugly and require a lot of work. I also have some concerns, because I like being a naysayer. Just ask Rohn.

Apologies if you've seen this sort of thing before, but I just sent an email to Armin of QuArK fame who's nobly trying to address this problem on his Call for Standards. I spent longer than I expected writing it, so I figure I might as well balance things out and hopefully waste at least that much of other people's time.

Having a Standard is Good But It Sucks Too

I think having a standard is a great idea. I have some technical concerns that I'm not necessarily qualified to back up or refute. ;-)

I agree that DLL's are a bad idea for portability. And from what little I know of Java, it's not a good idea because you would probably take a huge hit on performance. I don't know what the state of just-in-time or Java-to-native-code compilers is, but Java may not be the way to go because it is an interpreted [OK you nitpickers: "semi-compiled"] language. And my experience with Lisp tells me that at least some garbage collection methods would be *horrible* for real time games - there could be serious delays while a program does a major sweep of its memory. I don't know how Java handles garbage collection (and I suspect it may differ across platforms?) but garbage collection could be a big issue because it could also have an impact on speed.

I'm concerned about the complexity of some mods that may make it difficult or impossible to be able to automatically blend them. For example, two mods might redefine the same function, e.g. a teamplay mod and a "reduce damage" mod might both modify parts of the T_Damage function. Granted this won't happen all the time, but there are maybe 20 functions that have "core" functionality that are probably modified by most mod authors - e.g. client connect and disconnect, the procedure to run a frame, etc. Thus a "whiz-bang" mod combiner would need to combine mods at a sub-procedural level. Some mods use subtle rewrites of an entire procedure that may be hard to blend (I've done this myself anyways, although I've tried hard not to).

Assuming that we want to achieve this sort of capability, I'll spit out a semi-ignorant concern that I have with object-oriented approaches to the problem. It may be that the "proper" implementation would require finding and applying multiple methods to (effectively) the same object. E.g., to calculate damage, consult each mod that says something about damage and somehow "combine" all the results. I don't know if you can do that sort of thing; as I know it, it is up to the compiler/executable to figure out the appropriate method to apply to an object. But I'm not sure since I'm not an OO programming expert.

My Half-Baked C-Biased Object-Oriented Ignorant Approach Which Is Not Implemented At All

My half-baked thinking on how to approach this problem is as follows. For each separate mod, we register a subset of standardized "methods" that we want invoked in place of original code. Let's take the T_Damage example which is used by Mod X and Mod Y. If we can set it up so that when T_Damage is called, it first calls Mod X to figure out the damage percentage, then takes that result and feeds it into Mod Y, and then that's fed into the rest of the T_Damage function which remains unchanged, we can effectively get sub-procedural mod merging. I don't know what the performance hit would be, and I'm a bit rusty on how you store addresses of functions in C so that you can call them. (I've done it in the past but on a limited basis).

We could split T_Damage (AND, unfortunately, probably EVERY "standard" Quake function) into smaller, more manageable, standardized "chunks" for which we could define "override" methods. For example:

// I forget the proper arguments, and this is obviously pseudo-c code
T_Damage (attacker, inflictor, victim)
   if (! CanDamage(attacker, inflictor, victim)
      return;
   multiplier = CalculateDamagePercentage(attacker, inflictor, victim);
   if (multiplier == 0) return;
   norm_damage = CalculateWeaponDamage (attacker, inflictor, victim);
   total_damage = multiplier * norm_damage;
   victim->health = victim->health - total_damage;
   if (victim->health < 0) then
      KillPlayer(attacker, inflictor, victim);
   T_DamageAfterMethod(attacker, inflictor, victim);

All the function calls referenced in the above procedure could be standardized code chunks that can be overriden by mods. If no mod changes the chunk, we call the "original" Quake code. If multiple mods modify the same chunk, we execute each mod chunk function in some order. For example:

CalculateDamagePercentage(attacker, inflictor, victim)
  damage = 1;
  damage = ModXDamagePercentage(attacker, inflictor, victim);
  damage = damage * ModYDamagePercentage(attacker, inflictor, victim);
  return(damage);

Obviously we can't hard code this because the point is to add mods without recompiling. But, we might be able to implement this with linked lists of references to the explicit functions, but I haven't played with function pointers much so I'm not sure how it could be done.

For example:

CalculateDamagePercentage(attacker, inflictor, victim)
  damage = 1;
  if (DamagePercentageMethods != NULL) then
     method = DamagePercentageMethods->first;
     while (method) {
        damage = method(attacker, inflictor, victim) * damage;
        method = method->next;
     }
  }
  else
     damage = CallOriginalQuakeCodeDamage(attacker, inflictor, victim);
  return(damage);

Yep, Mucho Problems With My Half-Baked Idea, I Admit It So Leave Me Alone Unless You Have Even More Problems With It

Feedback to this page is included at sfeedback.html.

Even with this, there can be problems because maybe one mod's chunk "undermines" the actions of another mod's chunk. Also, each chunk must be written with the knowledge that it may be one of a possible chain of chunks that are called.

However, if 2 mods change the same chunk, then there is an indicator of a possible incompatibility which could be presented to the user. Each mod could define an API that lists all of the chunks it modifies. Potential problems could then be quickly identified and, possibly, addressed without changing source code; and even if a change is required for source code, this registration may be useful for telling how to change the code.

If this is a reasonable way to go, it requires a major reorganization of the original Quake source and a strict definition of an API. This could obviously be a monumental task if you want to support most mods. This approach still probably wouldn't be sufficient for some mods such as total or partial conversions. But it's an idea that I've been playing around with that I want no part of implementing ;-)

Links

Conclusion

I ain't doing it all, that's for sure.
Go to my No Frills Quake Mods Page.

I don't have a counter on this page. Does it mean that I do not care how many people visit it? No. It means that I don't want to know how FEW people visit it.

Email SteQve if you actually read this and actually care.