Closed Mira-Chronos closed 2 years ago
tbh I need to think this a bit more through. This is a step into the right direction, but this would have to be duplicated several times for other data files. And; on top of that I don't want the wiring between data files and the resource required become tightly coupled (like now).
Me thinking out loud
I think what is required is a class (like cFileNameSettings
) that gets a resource (ie, a dat
file, or directory, etc). But at the same time it will need to be feeded with the 'kinds of data' it has. Ie , the map you have now in cFileNameSettings
should be provided and not created in the constructor.
This way we can construct several cFileNameSettings
objects (I would probably rename it to cDataContainer
or something), and perhaps even have one cDataContainer
having multiple other cDataContainer
s.
So, we end up with having one big
data container class where we can ask resources, which basically would do:
The data container gets filled by some kind of construction mechanism (can now be hard-coded, but later it will be read from a resource definition
file). (ie for #78).
This way we decouple loading from a .dat
file and we decouple how we handle resources.
Now, resources should be 'found' by some unique key, and that key can be an ID (int
) I think. I am thinking about this from a mod perspective. Currently the resources are all hard-coded (somewhat) in the codebase. But I'd like to loosen the coupling so we can provide the resources and their references via ini
(or any other format) file. That means at the very least there needs to be a definition of all resources in an ini
file. Something along the lines of:
[RESOURCE]
ID=1
Filename=Quad.bmp
Type=BITMAP
<maybe other properties>
We don't need to build this whole "read resource definitions from a file" thing yet, but knowing I want to go there (for #78 ) it is good to have this abstraction somewhere. (even though we might still construct this 'resource definition' in code).
So, what does this come down to?
A single cDataContainer
class we set up (on game init, when loading game.ini
or something); that sets up all resources.
So somewhere in cGame.init
we would have a function setupDataContainers()
. Within this it will construct a cDataContainer
. Something like this (pseudocode):
baseDir = "data";
cDataContainer data = cDataContainer(
baseDir
);
font = {
id=1,
file="bene.ttf",
type=FONT,
...
}
// Add font resource
data.addResource(font);
// this is for the gfxdata.dat file for Allegro based files, so it knows it reads from a .dat file
quad = {
id=BMP_QUAD, // header ID (from gfxdata.h)
type=BITMAP
source=ALLEGRO_DATAFILE
File="gfxdata.dat"
}
data.addResource(quad);
obviously, adding a resource must check that the ID is unique.
Within addResource
we have something like:
void addResource(eResource resource) {
// check if ID already exists or not (if so, error!)
switch (resource.source) {
case ALLEGRO_DATAFILE:
// get data file from map string/datafile (based on file)
getOrLoadDataFile(resource.file).... // get from dat file
break;
case FILESYSTEM:
... open file, etc...
}
}
And when we want to use this, we would have to have a layer that can deal with these Resource
's, so it can draw, play sound, etc:
id = 1;
font = data.getResource(id);
gfxLayer->drawText(resource, "foo");
// or for fetching data from .dat file, for drawing:
quad = data.getResource(100); // this is the ID of the resource, not the gfxdata.h file
gfxLayer->draw(quad, x, y)
When we do this, we have only a few places left where we are tightly coupled to Allegro, and that is on resource loading and drawing (which are relatively easy to replace then). We could even add other file sources (ie .PAK
files or .MIX
files, or whatever).
Hope this makes sense?
Wonder what you guys think (@pbomta , @Akatsuki57 )
If I can thinking out loud ...
Yes and no.
Yes, total separation of data and program is a very good thing and I will modify my work on this PR to comply.
The current code is very dependent as you point out. It's work to decouple it and it's a great thing to take on that challenge.
No, platform abstraction is not a good thing. If we weren't developing a game, I would say quite the opposite: but we need performance.
One of the reasons I put forward is that the philosophy of the platform changes, depending on the platform. SDL2 brings the writing of textures to the GPU. If it's not to use this feature, you might as well do nothing because its whole point is to gain performance. Writing in the GPU means a change in philosophy and also performance gains. Let's imagine playing d2tm on a 4k screen...
For exemple !!! Not to do. If we have to rewrite d2tm with openGL, it will even be easy because SDL2 is very close to OpenGL but if we had to redo it in Vulkan for example, everything would have to be reviewed because Vulkan does not think like SDL2 at all and OpenGL.
I'm also not saying that you absolutely have to use all the features of the target library, but at least everything that gives it its flavor, which compromises the abstraction.
Still aloud: I propose to work on this idea in several stages. Firstly: 1) create a class that just reads ini files with d2tm specifics 2) take out of the code all the game data that is hardcoded. At the same time, reorganize the source code to best apply the principles of SOLID. https://en.wikipedia.org/wiki/SOLID
I am not experienced with SDL2 or OpenGL, but I can't imagine having one layer of indirection to be that much of a problem?
Just to be clear, I would still use direct access to all kinds of SDL objects for instance. So a Resource
would still hold a pointer to a SDL_Surface
for instance. I am merely talking about calls like blit
or drawSprite
or playSound
. We can wrap those around SDL
or Allegro
without losing (much) speed?
ah yes SOLID practices; we are already working with them; unfortunately 15-18 year old me didn't when I started D2TM :D
Made a few changes; looking good.
I have made it so that we can see which validations fail, example:
This way , when something is wrong we can see what is wrong and where. Which is kinda neat.
I love that we have a settings.ini
file now!
Need instructions for "data/gfxaudio.dat"