[Dev] Map File Organization

Quintillus

Archiving Civ3 Content
Moderator
Supporter
Joined
Mar 17, 2007
Messages
8,409
Location
Ohio
I've been diving into some map code (planning to add cities to the map), and had a few questions/thoughts on the code organization.

- Are LegacyMap/OldLegacyMap officially unused and/or obsolete? It looks like they aren't being used by the rest of the code anymore. If so, and if we want to keep them around for reference, I'd propose a Git tag as an option to keep them available if we're looking for them, but not in the main branch so we don't think they're in use.

- Maybe a stylistic thing, but I think we should generally keep one class per file, other than embedded classes. We currently have an interface and four classes in MapView, and it's about 440 lines, which to me seems like a point at which we should be splitting it into multiple files to make it easier to keep track of them.

- If we do create multiple files for the map, we should also move it into a folder, as LegacyMap/OldLegacyMap already are.

I wanted to check with others before making any changes, particularly as there may be changes-in-progress on MapView. But I'll likely be adding another class to that file, and it feels overcrowded, so I wanted to make the suggestion.
 
I'm still tempted to overhaul parts of MapView so I wouldn't be in any hurry to split it up into multiple files yet. In particular, ILooseLayer might be replaced with a different way of modularizing the code depending on how our architecture discussions/experiments shake out. We might want to replace it with a draw-objects-on-tile event of some kind. I had an idea for how that could work with delegates and actually made a little prototype a couple of days ago, though I hastily deleted it since it would conflict with the simplification I wanted to do. I should recreate that and post it in the architecture thread.
 
First off, I think there is a pretty important distinction between the map data and the map display code. Maybe they'll end up more intertwined than I'd like for optimization purposes, but we should have the ability to use non-PCX graphics, for example, without having to alter the objects that hold tile info like terrain, improvements, and such.

LegacyMap is currently important. The code in the main game scene right now *only* handles coast, plains, and grass. The LegacyMap is used by TempTile (an external scene) and can handle all base terrain. Actually there is a bigger difference, and come to think of it both Game.cs's version and LegacyMap's versions are important.

LegacyMap—legacy referring to 2004 Civ3 as opposed to a hypothetical C7 native map format—uses the file ID and index ID from real Civ3 save files to retrieve the right tile, so it's the actual display code we should be targeting.

What's currently in Game.cs (or if it got moved) generates a random map and then figures out which tiles to use based on the "one map tile graphic is four corners of actual map tile" challenge, but since it only handles 3 terrain types it needs to be greatly overhauled, but I think the base process is needed for when we start generating full-featured maps.

It's why the 3-tile code is still there; because it's a bunch of effort to generate even just the full base terrain map as opposed to loading the file/index references from a SAV map (where tile selection was previously done by the real game).

I forget what's in OldLegacyMap that I wanted, but I know I want to reference it later. But this project has several active developers now, and my temporized cruft can't continue to jam up the works, so I'm fine if we just tag the last commit having OldLegacyMap in GitHub and remove it from the current code. But LegacyMap is the future.


An alternative to what we have right now might be to start using the LegacyMap code now and leave out random generation, and now that I type that out loud, that makes the most sense. The gen code is feature-poor, and the current 3-tile map display is feature-poor, and LegacyMap is the future, anyway, so discarding those and forcing us to load real SAVs and/or hard-code a proper map for now makes more sense. (Until we get full-base-terrain-featured map generation coded.)

TL;DR: Random map gen is extraordinarily poor if better looking than before. Current 3-tile display code is not a base for going forward. LegacyMap *is* a base we can move forward on, but using it now forces us to load maps from SAVs and/or hard-code a map (presumably extracted from a SAV).
 
Great information! I like the point that we might want to try draw-objects-on-tile at some point. One Civ feature that I sort-of re-create in my editor but which has always been incorrect (though less incorrect now) is the equivalent of the right-click on a tile in-game, where it shows you the terrain type, yield, and a picture of the tile. That is one potential use of draw-objects-on-tile. Although now that I think of it (why'd I never think of it for the editor?), it could be created by grabbing a section of the view on the map, and cropping it diagonally. But nonetheless, I'm fine leaving the code the way it is for now.

Thanks for the clarification on LegacyMap. What you said makes sense, and I agree that it probably is for the best to use maps from BIQ/SAV files, and probably to include one as a resource to use as a default, for the time being. Having a full group of terrain types will also help with both presentation and reasoning about/implementing game mechanics.

We might want to rename it, though. It's counter-intuitive that LegacyMap is the future; it sounds like the past. And we've already been making improvements to MapView that aren't in LegacyMap, which could be problematic. We might have to reconcile what we want to keep from each.

I believe we are keeping tile/map data, and how we draw it, separate. In the city-drawing code I added, I reference the Tile and City objects from C7GameData to know if a city should be drawn (and for now, I only have one supported graphic).

Using non-PCX graphics is an area that's less clear at this point. The underlying data could be used with other formats, but how much the drawing code would have to change, I don't know.
 
I'm not sure what you mean by "draw-objects-on-tile". As long as we have a standard coordinates system we can just offset any drawing at x,y, and then what draws over what depends on what layer/Node2D it's in and the ordering of the layers. (Or we can invoke CanvasLayer and explicitly specify the draw layer, but I don't project a use for that outside of UI elements.)

Civ3 graphics overlay each other, anyway. It seems to me that they draw left-to-right, top-to-bottom, so the right-most and bottom-most image data will overlay what's left/above it. Tiles have a standard size, but nothing else seem to. Cities and mountains spill over tiles all over the place, and units vary in size. So in my mind, drawing "on a tile" is really just managing draw layer ordering and laying textures or sprites left to right, top to bottom.

I guess we'll need an anchor point (not as in Godot Control anchor point; as in graph origin I guess) for each tile. Center would seem to be intuitive, but it's unclear to me if Civ3 has a standard anchor point, and if it does I think it might be below center vertically at least. I haven't looked that closely though; just some speculating after seeing the variety of things that can be drawn "on" a tile.


I'm also not particularly concerned with image formats. To Godot, it's all Texture which is a grid of Color. The source of data makes no difference; it boils down to a grid of pixel colors. Basically every single unit of thing we draw on the map is going to be a child of Node2D. (Sprite, AnimatedSprite, etc..) ...

Oh, I think I see the confusion. I had to do it the hard way with PCX and FLC because they are literally so old nobody has any open-source C# libraries to read them, so I had to decode them myself. (Not too hard as they just use RLE and the formats are documented.) I actually haven' t added a "normal" graphic like PNG or JPEG with code yet, but the manual way in the UI is to import the file, and it makes a little file under .import folder, and you just assign that to the texture property of the thing (e.g. Sprite). Here is some code to do the same thing: https://docs.godotengine.org/en/stable/getting_started/step_by_step/resources.html

So basically all that code between the PCX file and assigning a texture to the Sprite (or whatever) is replaced by loading a resource, and the path is `res://path/to/thing.png` which is a relative folder path from the project root. (One thing I'm *very* curious about but haven't glanced at yet is how this works with additional PCK files and/or additional file hierarchies, but I'm confident it's a thing Godot has already figured out.) All my ugly/scary code goes away, and you have your Node2D child and a path to the Godot-recognized file format.

It only gets complex again if we have a need to. Like if there is some other media format we really want to use, but I imagine in such a case it would be a newer format with a C# library handy. *Or* maybe we'll find a pressing need to do something Godot can't do, like a multi-frame PNG or WebP...I have no idea if Godot supports those, but most everything I've touched in the past doesn't. Another example is if we want to use Adobe Photoshop or Gimp files directly we'll probably need to plumb a library for that format and convert to SetPixel, PoolByteArray, or the method you proposed to fill the texture(s).
 
I'm not sure what you mean by "draw-objects-on-tile".
draw-objects-on-tile would be an event raised by MapView that mods can receive to change how tiles are drawn. What an event is exactly hasn't been determined yet. My idea for events is that they would be like methods on a singleton object except the methods are all stored as variables (with delegates as their types) so they can be replaced at runtime. To make layers work we'd need multiple events (draw-city-on-tile, draw-units-on-tile, etc.) so that the appropriate one could be intercepted, or maybe we could set a Z coord on the draws but I don't know if Godot supports that in 2D. All this assumes that events are lightweight enough that we can raise millions per second without crippling performance.
Although now that I think of it (why'd I never think of it for the editor?), it could be created by grabbing a section of the view on the map, and cropping it diagonally.
The problem with this is that the tile's contents might extend outside of the diamond. I've thought about implementing the tile info popup and I think the way to solve it is with a little render-to-texture operation, i.e. modify MapView so it can draw to a viewport corresponding to a texture. I think that's something Godot can do.
 
To me, being able to mod how the map is drawn is something we shouldn't be worrying about at this point, given all the other things we have on our plate. I don't think even Civ4 allows that (maybe with DLL modding?), and I don't recall seeing any requests for modding how tiles are drawn, beyond things that we could implement fairly easily as a standard C7 feature (higher-res graphics, City View in mods).

Ah yes, the tile's contents aren't really a diamond problem. Drawing to a texture sounds potentially plausible for that. As for the mountain/etc. question Puppeteer mentioned, at least mountains, hills, etc. all have a standard size*. I don't remember what it is off the top of my head, but I implemented it in my editor. I want to say one of them is 88 pixels tall instead of 64.

Yeah, I think overall I'm not too worried about supporting newer formats. There will be a search order function, but that will be straightforward. For graphics with civ colors, we'll have to think of a way to handle newer (and notably non-palette-based) formats. But that seems like a worry for the future. We have enough to add now, and can always start out with higher-res terrain, city sets, etc. that don't require civ colors.

* There is a mod that uses the Empire State Building as a city graphic, which is way taller than one tile. I think it's called Manhattan? And there's a tactics-focused mod from China that manages to use an entire scene from another game as a ruins graphic, and it spreads across the map to make it look like it's the surface the battle is taking place on. But those are the extreme outliers I am aware of, and thus fall into the camp of "don't worry about for now".
 
Top Bottom