ML Map change

Want to discuss changes to the UOX3 source code? Got a code-snippet you'd like to post? Anything related to coding/programming goes here!
Post Reply
Sydius
UOX3 Apprentice
Posts: 171
Joined: Thu Mar 25, 2004 3:22 am
Has thanked: 0
Been thanked: 0

ML Map change

Post by Sydius »

I have decided to tinker with UOX3 a little bit in my spare time…

My first project is to add support for the new Mondain’s Legacy map0.mul, which is wider than the original (same height, though). At first, I thought I would just add a new map, but then I realized that, regardless of which map you use (the original or ML), you would want the same dynamic items and spawns etc. in at least the original portion of the map. You know, so that if you upgrade from the original map to ML, all your old doors and animal spawns would still be there.

That meant, in my mind, just increasing the width of the map upon initialization if it detects you using ML. Easy enough.

Even if my above idea would work, though, I foresee another, bigger problem: spawns and items in the new part of the map. Certainly, it might be feasible for people to use a world file meant for ML with the original map, and it should work, except for the stuff that is in the additional part… This means culling the world of any objects/spawns/NPCs upon initializing the server with the original map, and then putting the culled ones back upon saving… basically leaving them there but disabling them somehow (I would prefer to not just delete them incase they just accidentally used the wrong map once or something).

Any comments before I go about implementing this? It should, overall, be pretty easy, I hope. Only reason I care is because Xuri got me to d/l ML instead of the original, heh.
User avatar
Xuri
Site Admin
Posts: 3704
Joined: Mon Jun 02, 2003 9:11 am
Location: Norway
Has thanked: 48 times
Been thanked: 8 times
Contact:

Post by Xuri »

Well - beta or not - it'll be an issue in the future in any case =) And considering the rumors of a "one client only"-policy from EA, they might apply this map0.mul change to the older clients as well, to make them all similar.
-= Ho Eyo He Hum =-
Sydius
UOX3 Apprentice
Posts: 171
Joined: Thu Mar 25, 2004 3:22 am
Has thanked: 0
Been thanked: 0

Post by Sydius »

No, actually, they were clever about the way they did things. Because of the way that the map is formatted, and because they did not change the height, either client should, theoretically, be perfectly capable of using either map. Due to the block system, it should not, theoretically, ever need to load the additional map portion unless you try to go to it. In addition, the old client can use the new map because only the width was changed, which does not throw off the alignment – there is just extra leftover data.

It is an issue, however, since UOX refuses to work with the new map. Perhaps for now I will simply tell it to ignore the additional data like the client would until someone decides to tackle the issue of fully supporting ML.
Sydius
UOX3 Apprentice
Posts: 171
Joined: Thu Mar 25, 2004 3:22 am
Has thanked: 0
Been thanked: 0

Post by Sydius »

You know, really, the current system is pretty flawed because it assumes that all maps use a fixed format for naming and the sizes are hard-coded.

I think there should be a CMapInfo class or something to store that information, and I think that information should be loaded from a file at initialization.

That would fix this problem and even allow for custom map sizes since some third-party clients allow custom sizes.
User avatar
Xuri
Site Admin
Posts: 3704
Joined: Mon Jun 02, 2003 9:11 am
Location: Norway
Has thanked: 48 times
Been thanked: 8 times
Contact:

Post by Xuri »

Unless there are any drawbacks to doing it that way, I second that opinion. Better support for custom maps = more options for creative people, at the same time as we could stop worrying about future map-expansions, as UOX3 would read those new files automatically as well?
-= Ho Eyo He Hum =-
Sydius
UOX3 Apprentice
Posts: 171
Joined: Thu Mar 25, 2004 3:22 am
Has thanked: 0
Been thanked: 0

Post by Sydius »

Yeah, just have a file that contains a list something like this:

INDEX MAP STATICS INDEX WIDTH HEIGHT
0 Map0.mul Statics0.mul Staidx0.mul 6144 4096

Or something like that.

Two things I would have to figure out before implementing such a thing would be:

What is the standard for configuration files like this? Is there generalized code for reading in configuration files already? I don’t think this should go into the ini file, but I suppose it could.

How exactly are items/NPCs/players stored in memory in relation to which map they exist on? As in, how does the server keep track of which map something is on? An index (like I have above) or something?
Maarc
Developer
Posts: 576
Joined: Sat Mar 27, 2004 6:22 am
Location: Fleet, UK
Has thanked: 0
Been thanked: 0
Contact:

Post by Maarc »

Yes, there's generic INI reading code in there, it's called cScript/ScriptSection. We use it in more places than just DFNs, such as regions and jails.

Code: Select all

ourRegions = new Script( regionsFile, NUM_DEFS, false );
Then you can either iterate through one at a time (begin, end, ++ stuff), or look for a specific section.

It just means it needs to be formatted in a similar fashion ( [] header, tag=value pairings and so on)
Sydius
UOX3 Apprentice
Posts: 171
Joined: Thu Mar 25, 2004 3:22 am
Has thanked: 0
Been thanked: 0

Post by Sydius »

I will try to implement a map info class after I fix another bug I am currently working on. Trying to work my way up so that I can get a better feel for the code.

In the mean time, I submitted a fix to Xuri that at least allows ML users to log in using UOX – it basically just tells UOX to ignore the extra data and treat it as the original map.
Maarc
Developer
Posts: 576
Joined: Sat Mar 27, 2004 6:22 am
Location: Fleet, UK
Has thanked: 0
Been thanked: 0
Contact:

Post by Maarc »

There are actually more than just a map issue with regards to this sort of stuff, unfortunately. For instance, pets are an issue with the new width, I believe.

As it stands, when you "mount" an NPC, the real mount character doesn't get deleted (as it used to), but gets shunted away to a "safe" location. Around 7000,7000 I think. I don't think that's directly accessible under the new map, but not sure. You'd then have to be careful, at least, with logic dealing with mounts.

As an aside, do a file search for 6144 and 7000. There's too many appearances, I think, so we obviously use 6144 hard coded in a few spots. For now, anything between 6144->7000 gets lost.

And there's also the impact on mapRegions. We, at the moment, save a fixed number of files, based on how wide/high the mapregions get allocated. A wider map implies more files. I know that Xu's WB should be able to cope with it, but other tools may not.

And there's the other issue with mapRegions, which I never got sorted out entirely. There are enough mapRegions in each world to cover the biggest map size. So Malas has the same number of mapRegions as normal Brittania. It was something I never did sort out terribly well. It worked for the time being, but it means there is dead space being wasted in there.

As it stands, the existing map code can use a map of any known size in any location, at least on the server. You could have 4 (I think that's the max) brittania or malas sized ones, or any number of variations. While it makes it easier to support new maps to put this stuff out to a file, let's face it, any client that introduces a new map introduces a lot more than that, which means supporting that map isn't going to just be that easy. But hey, it's the will of the people, right? :)
lingo
UOX3 Novice
Posts: 55
Joined: Thu Jul 07, 2005 12:26 pm
Location: Taipei, Taiwan
Has thanked: 0
Been thanked: 0

Post by lingo »

Sydius wrote:Yeah, just have a file that contains a list something like this:

INDEX MAP STATICS INDEX WIDTH HEIGHT
0 Map0.mul Statics0.mul Staidx0.mul 6144 4096

Or something like that.

Two things I would have to figure out before implementing such a thing would be:

What is the standard for configuration files like this? Is there generalized code for reading in configuration files already? I don’t think this should go into the ini file, but I suppose it could.

How exactly are items/NPCs/players stored in memory in relation to which map they exist on? As in, how does the server keep track of which map something is on? An index (like I have above) or something?
There are distinction between static and dynamic items. Static items are stored on Statics0.mul Staidx0.mul, the data are managed by mapstuff.h. The dynamic items and NPCs/players, (NPCs/players are always dynamics?), are managed by regions.h. All the data is indexed on the world # (0, 1, 2, 3). That my understanding.

I am also working on the map stuff right now. I am also working on some change to the code right now. Should we discuss our changes before some code conflict develop?
User avatar
Xuri
Site Admin
Posts: 3704
Joined: Mon Jun 02, 2003 9:11 am
Location: Norway
Has thanked: 48 times
Been thanked: 8 times
Contact:

Post by Xuri »

Looks like we have to solve these issues soon somehow, seeing as all older clients will be patched up to full ML-status:
http://www.uo.com/uoml/ wrote: How to get the Ultima Online™: Mondain’s Legacy game client
To play Ultima Online™: Mondain’s Legacy, you will need the full Mondain’s Legacy game client installed on your PC. There are three ways to get the game client:

1. PATCH -- Install a previous version of UO from CDs, or simply allow the version you have installed to patch itself. All installed UO clients will patch themselves with the Mondain’s Legacy content in August. On launch day, if you have upgraded your current account, you will be able to play the new content immediately.

2. BACK-UP CDs – You will also be able to order back-up CDs for $4.99 starting Aug. 30. These CDs will not come with the registration codes you’ll need to play with, but they will come in handy if you need to re-install the game for some reason.

3. DOWNLOAD THE CLIENT – You will also be able to download the client from various download partners. If you don’t have CDs and have a broadband internet connection, this will be the best solution. Links to the download partners will be released before Mondain’s Legacy launches on Aug. 30.

Don’t forget! Having the Mondain’s Legacy game client does not mean you are entitled to play the new content. For that, you will need a Mondain’s Legacy Upgrade Code or Account Creation Code. Those will begin pre-selling on Aug. 14.

Keep watching www.uo.com for the latest news about Mondain’s Legacy!
-= Ho Eyo He Hum =-
Sydius
UOX3 Apprentice
Posts: 171
Joined: Thu Mar 25, 2004 3:22 am
Has thanked: 0
Been thanked: 0

Post by Sydius »

I am not going to be working on this issue any further anytime soon since it is obviously much more complex than I thought...
giwo
Developer
Posts: 1780
Joined: Fri Jun 18, 2004 4:17 pm
Location: California
Has thanked: 0
Been thanked: 0

Post by giwo »

Obviously this is a problem of flexibility.

The problem is two-fold. On one hand we have code that has been around for quite some time handling a constant size map. From there modifications have been made to allow duplicate constant size maps, and then fit whatever we wanted within those size limits. On the other hand we have newer code that handles the dynamics in those maps, allowing for, once again, a constant size, and working with any duplicate map that was less than or equal to that size (albeit a bit wasteful).

What we NEED, is a way to allow UOX3 to be more flexible with ALL maps, be it the first one, or the 30th one.

Firstly, we need to decide how many worlds to allow, I would say there would never need to be more than 255 seperate maps, and thus an unsigned char would be an acceptable container for the worldnumbers.

Secondly, how do we want to make flexible the size limits on maps. I would say it MUST be on a map-by-map basis, rather than allowing anything smaller to fit inside a single size-limit, lets define each one individually. My vote in this scenario would be to have a seperate .ini file that looked something like this:

Code: Select all

[MAPS]
{
     TOTALMAPS=#
}

[MAP 1]
{
     MAP=Map0.mul
     STATICS=Statics0.mul
     STAIDX=Staidx0.mul
     X=7000
     Y=7000
}
From here we load in each map file when UOX3 starts, and error out if any fail to load properly. This would require that our current MapRegions() (which are stored as an array[][][]) be changed to a resizeable container, like a vector.)

For instance

Code: Select all

class CMapWorlds
{
private:
     std::map<UI32, CMapRegion> mapRegions;
public:
     CMapRegion& GetMapRegion( UI32 toGet );
};

Code: Select all

std::vector<CMapWorlds> mapWorlds;

Code: Select all

CMapRegion& GetMapRegion( CBaseObject& i )
{
     CMapWorlds& ourWorld = mapWorlds[i.GetWorld()];

     return ourWorld.GetMapRegion( calcserial( i.GetX()>>8, i.GetX()%256, i.GetY()>>8, i.GetY()%256 ) );
}
I'm at work currently, so I may have more thoughts on this once I can actually look at the source (specifically in relation to the actual map handling).
Scott
Sydius
UOX3 Apprentice
Posts: 171
Joined: Thu Mar 25, 2004 3:22 am
Has thanked: 0
Been thanked: 0

Post by Sydius »

That is what I was thinking, but I did not realize how intertwined it all is…

I think there should be a very clear boundary between a map and the rest of the system – you should be able to interchange a map or even the entire mapping system and have it be completely transparent to the rest of the system. There should be a simple and constant interface that is easy to use and understand that allows somebody to load map and get information about any given coordinate, block, or region.

I also think that anything map-dependant should be stored inside the mechanics of the map, however I believe it should ONLY be stored, for purposes of clear identification of ownership – provide methods for alteration, inclusion and elimination for anything within it, but have the maps be the global containers for all objects which are location-dependent (players, items, teleporters, etc.). That not only makes the code much easier to understand, but it would also eliminate all this map-id mess (at least outside of the map object).

I envision super-easy and clear access something like this:

CMap *Brittania = CMapManager::GetSingleton().GetMap(“Brittania”);

Brittania->AddObject(Object, x, y, z);

Vector<ObjectPtr> ObjectList = Brittania->GetObjectList(x1, y1, z1, x2, y2, z2);

… do something to those objects …

You get the idea… I think it would be clean and elegant.

Then again, I just made all this up as I went… I will probably think it is crappy in another 5 minutes. Oh well, by then I will have forgotten this idea anyway.
Sydius
UOX3 Apprentice
Posts: 171
Joined: Thu Mar 25, 2004 3:22 am
Has thanked: 0
Been thanked: 0

Post by Sydius »

Map Brittania = MapSystem::getSingleton().getMap(“Brittania”);
Player Syd = Brittania->FindPlayer(“Syd”);
Item CattleProd = Syd->FindItem(“CattleProd”);
Player Xuri = Brittania->FindPLayer(“Xuri”);
Syd->Use(CattleProd, Xuri);



Or something like that :-D
giwo
Developer
Posts: 1780
Joined: Fri Jun 18, 2004 4:17 pm
Location: California
Has thanked: 0
Been thanked: 0

Post by giwo »

I agree that it should be as self-contained as possible, but there you find more difficult issues to tackle.

For instance, do you really want the statics/map handling in the same area as dynamic/worldsave handling? Sure, it's dealing with the same map, but it's two very different sections of code which don't really intermingle whatsoever (the dynamic doesn't care about the map past being in a valid location on it, the static doesn't care about the dynamics at all).

My belief is we should have something like this

CMapHandler

CMapHandler is our base class. It has one instance, handles all loading of the maps, miscellaneous functions that do not need seperate instances.

CMapHandler::CWorldMaps

This is our instance class, it will contain two classes one for dynamics and one for statics. This will be based from the mapWorlds vector.

CMapHandler::CWorldMaps[]::CMapStatics

This class will be doing anything specific to reading in each maps static information.

CMapHandler::CWorldMaps[]::CMapRegions

This class will handle all dynamic regioning and saving, it would contain the map I indicated in an earlier post.
Scott
lingo
UOX3 Novice
Posts: 55
Joined: Thu Jul 07, 2005 12:26 pm
Location: Taipei, Taiwan
Has thanked: 0
Been thanked: 0

Post by lingo »

giwo wrote:
My belief is we should have something like this

CMapHandler

CMapHandler is our base class. It has one instance, handles all loading of the maps, miscellaneous functions that do not need seperate instances.

CMapHandler::CWorldMaps

This is our instance class, it will contain two classes one for dynamics and one for statics. This will be based from the mapWorlds vector.

CMapHandler::CWorldMaps[]::CMapStatics

This class will be doing anything specific to reading in each maps static information.

CMapHandler::CWorldMaps[]::CMapRegions

This class will handle all dynamic regioning and saving, it would contain the map I indicated in an earlier post.
I think abstracting away the difference between CMapStatic and CMapRegions will be a better choice. the classes remain, but we only expose a new class CMap, which wrap CMapStatic and CMapRegions.

Because some functions LineOfSight or class cMovement will loop through both CMapStatics and CMapRegions. You realized that a single interface to accessing the world grid will simplify the logic of a lot of classes. It also eliminate some bugs because the classes don't have to loop through region list to find a particular "things", which is easy to get it wrong.
Post Reply