RunUO Community

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

Question about RunUO source...

Status
Not open for further replies.

Courageous

Wanderer
Question about RunUO source...

The RunUO source is filled up with things like:

Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.

This is what a professional software person calls a "magic number," meaning a number that appears as is, by itself. Is there some particular reason that the RunUO team opted to inline all special codes as magic numbers, instead of creating a namespace that packaged all the special numbers into well-named variables within the namespace?

If ths were done, the equivalent line of code would be something like:

Caster.SendLocalizedMessage( TARGET_CANNOT_BE_SEEN );

This has the added advantage in that any global changes to any of these special numbers has a single point of control....

C//
 

Bmzx007

Wanderer
Quite simply explained.

Each UO client, has a cliloc.(x) file. (x) being your language shorthand (Enu, Rus, Ger, Jap, etc).

That file contains a list of however many cliloc indexes, with values attached to them.

When the UO server sends the number to the client, it displays the appropriate value. The number sent (Which you are inquiring about) is the index number.

This is done because it heavily saves bandwidth sending the small number, compared to the whole string. You would only send the whole string if you were doing custom messages. But even then, modifying the cliloc to add your own isnt that difficult.

If you had thoroughly searched the source, you would have found these numbers do not exist anywhere. And if you had traced back the SendLocalizedMessage method, you would have found that it sends the data to the client for further processing.
 

Courageous

Wanderer
No, that's not my question. My question is why it is encoded as a *magic number* and not defined elsewhere in some other space. In this other space, it would of course still be a number; it would, however, also have a literate name; e.g.,

class Definitions
{
public static int TARGET_CANNOT_BE_SEEN = 500237;

// ...
}

You could then use Definitions.TARGET_CANNOT_BE_SEEN instead of 500237, even though 500237 is the exact same compact number sent over the wire later....

Using this approach, code no longer includes the number directly, but rather indirectly through its symbol. This has the advantage that all usage points in the code are choke pointed at one definition. Global changes are easy. And the purpose of the variable is self encoded.



C//
 

ArteGordon

Wanderer
The answer to your question is that the index numbers in the client are not subject to change (or I should say have not been subject to change in the history of the client and probably will never be changed) so there is no real need to add an additional level of symbolic indirection.

So practically, the only thing that adding a symbolic reference instead of actual numbers would do would be to enhance readibility (assuming you came up with a reasonable symbolic naming scheme), but that is better accomplished by adding the more complete string reference as a comment, and that is how it is currently done.

What you suggest would be a lot of work (there are a lot of cliloc values), and wouldnt really add any functionality since you would never be changing the value of any of those symbolic references.
 

Courageous

Wanderer
What you suggest would be a lot of work,...

Well, perhaps. Does visual studio have automated refactoring capability yet? Although I could see how this would be a problem. It's not like one can just go globally search and replace (in all files) the number '1', and hope that the replacement was semantically consistent. On the other hand, 500237 might be unambiguous. :)

But it's not just readability, mind you, but also writability. The readable way also happens to have a mneumonic, and that allows developers to remember and type things that are, umm.... easy to remember. :) It's also self-commenting. One may or may not always comment a magic number (hint, these comments that you say can be written frequently are not), but the mneumonic always has to be spelled correctly to work. The other advantage is that a wrong number can easily be mistyped, but a mneumonic can only be mistyped to the degree that it's lexigraphically identical to another mneumonic. That's unlikely. So using this approach, you make it so the compiler is likely to catch errors.

And all these reasons are why this approach is considered a "best practice" in software engineering circles.

Of course, I'm not the guy who'd have to run the whole source base through a refactoring tool, ... :)

C//
 

Courageous

Wanderer
most of the localized messages are commented, so whats the big deal?

Most of the magic numbers are not commented.

I know exactly what you want and are talking about,...

Good.

...that RunUO isn't designed that way...

Consider this a friendly design review.

Have a good one.

C//
 

ArteGordon

Wanderer
There isnt anything wrong with your idea, but also note that there are many available clilocs that are not actually referenced in the source, so adding support for a fully symbolic cliloc referencing system would mean adding symbolic references for all possible clilocs not just substituting existing cliloc references in the source.

Again, a lot of work.
 

Courageous

Wanderer
ArteGordon said:
There isnt anything wrong with your idea, but also note that there are many available clilocs that are not actually referenced in the source, so adding support for a fully symbolic cliloc referencing system would mean adding symbolic references for all possible clilocs...

Nah. I wouldn't do it that way. I'd do it on an as-needed basis. One of the basic principles of agile programming is that one avoids loading down code with unreferenced things. And I, for one, am a fan of that principle. Adding in clilocs you weren't using yet would be like adding in lots of methods and classes you're not using yet: a bad idea unless you anticipate an immediate need...

C//
 

Courageous

Wanderer
I don't know of any custom scripts that use localized messages, so whats the point of making them more user friendly?

I'm referring to all magic numbers, phantom. This is a software engineering technical term. The use of a localized message in the example was just one instance of a magic number. There are many others. Look. Magic numbers are a bad programming practice. While it's true that anyone can armchair quarterback someone else's code, I do believe I've made my previous remarks as helpfully and politely as a I possibly can. You can either learn from them, or not. It's up to you.

Another suggestion I have for you is to avoid saying to people "you don't know what your talking about". People won't take it nicely, okay?

C//
 

Ray

Sorceror
There are some reasons not to do that in a general list.
  • As already said, it would be quite a lot of work. My cliloc.enu that contains that stuff is 1.5mb large.
  • It wouldnt increase readablility or writeability, because some of those localization texts aren't unique. There is a high chance to find the same text with a different number for different purposes. This is because not every text has a similiar text in foreign language.
  • It's also a thing of staying up-to-date. RunUO isn't conrolling the content of the translation files, therefor, EA can randomly change them. They are not truely constant as magic numbers should be.
  • Most scripters doesn't need it, because the localization viewers are very handy with full text search :p

But at last, if anybody needs that, he can do it. Especialliy for the often needed messages, it 'can' improve readability, but that depends on the scripter. I, for myself, like to simply define a const within the script i need it.
 

Courageous

Wanderer
You dont understand what your talking about...
I have never taken comments about code that people couldn't code themselfs, very good, so excuse me.
I still don't think you know what your talking about, and don't really care if you take it good or bad.

Taken from the TOS of this board:

Rules:

* Be respectful of others

This is the FIRST rule.

C//
 

Courageous

Wanderer
Ray said:
There are some reasons not to do that in a general list.
It's also a thing of staying up-to-date. RunUO isn't conrolling the content of the translation files, therefor, EA can randomly change them. They are not truely constant as magic numbers should be.

But at last, if anybody needs that, he can do it. Especialliy for the often needed messages, it 'can' improve readability, but that depends on the scripter. I, for myself, like to simply define a const within the script i need it.

To me a "magic number" is a hard coded number, directly in a file. These are to be avoided.

To achieve this, a definitions file is set up somehow. So, for example, if EA did elect to change a value, then one could simply change the value at a single point of control. Staying up to date becomes much, much easier! Instead of having to hunt and peck through all possible impacted source files, one simply opens the definitions file for the type and edits it exactly one time.

Your 1.5mb file probably has strings and so forth; these are not needed for this purpose, only a mapping of symbols to integers. And completeness really isn't required; the only thing that is required is that every single meaningful number addressed in code refers to its symbolic definition instead of the number...

Note that I'm not at all limiting my comments to just the client strings. Anything and everything that is a number that "stands for something other than a number" is a candidate for removal. That's most use of numbers that aren't meaningful in their own right.

There are counterexamples. Like gold = 1000; this is meaningful by itself. It's unambiguously clear. As is str = 80; and so on.

I guess I'm just a big code clarity freak. What can I say? :)

C//
 

Zippy

Razor Creator
I would have to say given that the CliLoc files are not controled by us (and thus can be completely changed whenever OSI wants) and give the fact these files contain thousands of strings, it just doesn't seem like a great idea to symbolically define all of these things inside the RunUO source.

In short: We're lazy? All the number are at least well commented.
 

Courageous

Wanderer
I would have to say given that the CliLoc files are not controled by us (and thus can be completely changed whenever OSI wants) and give the fact these files contain thousands of strings, it just doesn't seem like a great idea to symbolically define ALL of these things inside the RunUO source.

*bonking self on head real hard*

I never said "allllllllll", man!

If a cliloc code can be changed at any time, the very best strategy one can possibly have is a central location to adjust that in the event the change happens. This is one of the major advantages of a definitions file.

'Course, mind you I'm being... shall we say?... persnickety. Reviewing the code as we speak, I only have three complaints. 1) abuse of magic numbers. 2) everything's thinly commented indeed, and 3) Ah, lemme see:

You know the autocompiler? Why don't you compile to intermediates and leave them in place? Then, as you start the server, do a "make" like action of checking the timestamps for all the intermediates and source, and only compiling those .cs files that have more recent dates than their object files?

Anyway, I realize beggars can't be choosers.

Has anyone looked into putting a 'make' like functionality into the core? I casually looked at the way the assemblies were crafted, but this appears to be a .cs'ism that I'm not familiar with. Are the object files generated in temp or some such?

Anyway, my few nits aside, I'm impressed with the general coherency of this work. I don't often find this level of clarity in the hobby community... perhaps we are professionals, except being a bit lazy? :)

C//
 

Atomic

Wanderer
This gave an ideia!
Make a program that goes thru all scripts and compiles the enum with the clilocs used AND messages without cliloc. Then another program goes and compiles a custom cliloc for you out of it XD~~
 

arul

Sorceror
Whats the benefits of your idea ?
Why would we need 500+kb class of "nothing" in fact ?
Yes, its an option that would make your code, let's say, more semantical, but you would still need to search for each single entry if you want to use it, even though we can use an IntelliSense I can't even imagine list of 50k symbollical entries.
Although, making the application that would extract the entries from the cliloc in appropriate format is matter of little while, so make it, post it and we'll see if people will like it...
 

Courageous

Wanderer
I also know the rules better then anyone, so I don't need some newbie telling me to be respectful when I have tried to show respect only to be told "I don't understand what your talking about", I don't need ANYONE telling me I don't understand something.

That's was my whole point, Phantom. I never once told you that you didn't know what you were talking about, but you told me three times (3!) that I didn't know what I was talking about! Now why would you treat others in a way that you yourself do not want to be treated?

C//
 
Status
Not open for further replies.
Top