Gamemode Script Layout
#21

I'm writing a mini-games mode this is the approach i have taken.
  • Defines.
  • Samp and third party includes (max players in between, redefined directly below a_samp).
  • Enums
  • Global variables.
  • Gamemode custom includes (so they can use global variables very easily)
  • Main gamemode code
Even some of my callbacks are in separate files and i have not bothered hooking them. Callbacks like OnQueryFinish and OnDialogResponse that take up a lot of room i tend to put in their own file.

Until about a year ago i just used 3rd party includes and had all of my code in one file. I wrote a fairly large gamemode. When i had a break from scripting (about 3 months only) i came back to do some updates and found the code was just too unmanageable. It looked like obfuscated code, even though i never intended it to be, it was ok for me to update before i had the break. This is the reason i started keeping things in different files. So far so good. If i want to add something to a game, i just open that games file and add it. Without having to endlessly search a large gamemode. Which still takes a long time using Ctrl+F or Ctrl+G. Time which could be better spent adding new features.
Reply
#22

i do it like this

1.defines
2.forwards
2.includes
3.callbacks

thats all

i have an include called vars.inc where i put all the variable declarations, functions.inc where i put all the stocks, timers where i put all the timer publics, commands.inc where i put all my commands so if i have to show the login screen on player connect i just do ShowLogin which is a stock found in my functions.inc and LoginPlayer() under OnDialogResponse to login the player (also found in the functions include).

Apparently my includes are bigger than my pwn xD

I try putting most of the long code away from my pwn like i have a stock called ServerInit which loads all the OnGameModeInit() stuff too. feel its more organized
Reply
#23

I use one .pwn with includes, simple definitions and callbacks only, rest, including all globals, is in 17 includes grouped by their job (one for timers, one for internal database arrays, one for admin script, one for commands, and every major feature like housing, police, trucking, companies, objects in their own includes)

Seriously, stop putting everything into one big file, this is one of the "C programmer's rules" [aka noob's]:
[translation, old post from newsgroups]
Quote:

1. Use a lot of global variables
2. Give them mysterious names, like X27, a_gcl or Horacy
3. Write everything in one big .h file
4. Implement whole program at once
5. Use macrodefinitions to emulate Pascal
6. Imply that compiler will take care of all the details you don't exactly understand

It makes the file totally cluttered, unreadable and hard to maintain, I did the same mistake before and after rescripting I no longer have troubles with finding anything important

Also take care about forwards, do you really need all your functions to be public? [needed for timers and remote calling only], then put forwards BEFORE the function, not at top of script because it has no use there and you don't need to jump through file to delete function + forward

Also, stop using some weirdass .map readers unless you dynamically load maps, convert and put your maps directly into script (new include of course), if you want to laugh at that then fuck you and remember what happened to New Dawn and all their fabulous maps
Reply
#24

Quote:
Originally Posted by AlonzoTorres
View Post
I get a negative feeling about your post and it's kind of boring to read to be honest. We wanted to know what layout different users have but you just ramble on about how you're intrigued and that we should read more books and stuff. Why not relax with your academic chit-chat and just tell us how your layout is. The only thing I got from your text is that one should not arrange the code by declaration type instead one should arrange by function. You have to understand who your audience is and adapt your language and the information given in that way.
i find the quality of his posts helpful (i enjoy reading so). you really don't learn anything by simple responses (just like the til thread..) - yes it's what you want, but sometimes you just need to soak some sun to have some fun!

anyways, ot - i write in one mode. i'm the only dev and i get things done much quicker. fine me later..(i do have one semi-abandoned project done with some y_master help and separated files (so i gave that a try, but it's a tdm i'll finish that later)
Reply
#25

Quote:
Originally Posted by AlonzoTorres
View Post
Thank you for the answer. I never said that I wanted to be spoon-fed nor did I say that I only wanted one word for an answer. I simply said that you could be more specific at times and make it easier for those who wants a quick answer. You could do this by segmenting the information with as you describe it, "dumb" or as I would say, clear statements at first followed by a more in-depth discussion. No need to feel insulted and no need for insulting me with silly statements such as "and not expect everything to be spoon-fed to you here"... Only trying to help out you know!
Fair enough. Sorry.

Quote:
Originally Posted by Gryphus One
View Post
The main problem I see with this is there's a limit in the number of filterscripts you can run at the same time.

By the way, Y_Less, there's something I want to know your opinion on: I too split my code into different includes, hooking the callbacks and leaving only a few lines in the .pwn file. And generally I'm happy with this way of scripting, however there's something that clearly is less optimized than if I were writing all my code in the .pwn file: loops. Imagine there are several includes in which I have a for loop in the same callback, for example I loop through all vehicles in OnVehicleSpawn. If I hook that callback in those includes and put a loop inside, that loop will be repeated for that callback as many times as includes have that code, however if all that code were in the .pwn file I could loop only once and put all the code from all those includes into that single loop, right?
Short answer: I don't know.

That is a VERY good question, and now you've got me thinking about possible solutions - I don't have one at this time sadly. Something like "ptask", which is explicitly designed for per-player timer would be good; or "PSF:" functions, which are a bit of a hidden feature in YSI but again abstract per-player functions. As for a more general solution for your question, I just don't know unfortunately.

However, you would have to look at how much overhead the actual loop introduces. Most of the time spent on loops is spent doing the code inside the loop, not spent on doing the looping itself. The time taken to run code within the loop will be the same whether you have it in 1 loop or 10 loops (more or less, excluding code that needs to be replicated). If you can use "foreach" for things as well you may even get close to having trivial additional overhead for the extra loops. Of course, it will never be as good as only having one loop.

I was trying to imagine a solution in which hooks could be made aware of inner loops and handle those too, but I don't think that is at all possible. For one thing you would need to handle code run before and after the loop to set things up and destroy them. For another thing, you would have to call each hook for every loop iteration. Both of those problems can be solved, but I think the code required to solve them would be greater and slower than the code used by extra loops, so you are better off sticking to them.

The final question is: Is it even a problem? Yes it is "slower", but is it actually "slow"? If the slower version still runs fast enough to run the server, it isn't something that needs worrying about. If this changes, THEN you can start trying to optimise - bear in mind that readable code is much more useful in the long term than optimised code.
Reply
#26

What I like to do, or rather, what I try to do, is to make different files for different parts of the gamemode.

As Y_Less said, not sorting the books by color, but by topic.

Some of the files that I include back into my main gamemode are:
- Initiation
- User initiation
- User damage things
- Vehicle purchase things
- Vehicle damage things

Well, basically, new file for a new feature. If I for instance decide to create a new feature that allows users to purchase and place furniture, I would make a brand new file for this feature on its own. That way everything is easy to edit, and the file for a quote on quote _bugless_ feature that I do not want to alter does not have to be opened at all.

Of course I sort things into different folders and such, but that's the main point of it all anyway.
Reply
#27

I read some really neat articles on "Leaky Abstraction" check them out:

http://www.joelonsoftware.com/articl...tractions.html

http://www.claire-blackshaw.com/blog...-abstractions/

I think they will tie in pretty well with this thread.

tl;dr?

The concept discussed in the articles is basically about abstracting too far or unnecessarily from the fundamentals and the complex problems "leaking through" to the simple layer on top and causing more problems that the developer using the simple method has no idea how to address.

Here's a SA:MP example where IsPlayerInAnyVehicle is just a glorified vehicle ID validation check (I don't actually know the internals of this function, this is hypothetical). You run a loop and check IsPlayerInAnyVehicle then if they are, GetPlayerVehicleID and do something. But you may as well just get the vehicle ID on every iteration and just check if it's valid thus only calling one function instead of two that pretty much do the same thing only one returns a normalised result.

Another example of the second point: I am using YSI to develop a higher level player-interaction library, SIF. If I upgrade to YSI 4.0 because I need a feature that is only in YSI 4.0 and y_hooks breaks while Y_Less is on holiday, I am completely stuck as I have no idea how y_hooks works or how to fix it.
Reply
#28

What's the problem again sorry?
Reply
#29

Quote:
Originally Posted by Ceathor
View Post
What I like to do, or rather, what I try to do, is to make different files for different parts of the gamemode.

As Y_Less said, not sorting the books by color, but by topic.

Some of the files that I include back into my main gamemode are:
- Initiation
- User initiation
- User damage things
- Vehicle purchase things
- Vehicle damage things

Well, basically, new file for a new feature. If I for instance decide to create a new feature that allows users to purchase and place furniture, I would make a brand new file for this feature on its own. That way everything is easy to edit, and the file for a quote on quote _bugless_ feature that I do not want to alter does not have to be opened at all.

Of course I sort things into different folders and such, but that's the main point of it all anyway.
Except folders, that's what I too do.

Quote:
Originally Posted by [HLF]Southclaw
View Post
I read some really neat articles on "Leaky Abstraction" check them out:

http://www.joelonsoftware.com/articl...tractions.html

http://www.claire-blackshaw.com/blog...-abstractions/

I think they will tie in pretty well with this thread.

tl;dr?

The concept discussed in the articles is basically about abstracting too far or unnecessarily from the fundamentals and the complex problems "leaking through" to the simple layer on top and causing more problems that the developer using the simple method has no idea how to address.

Here's a SA:MP example where IsPlayerInAnyVehicle is just a glorified vehicle ID validation check (I don't actually know the internals of this function, this is hypothetical). You run a loop and check IsPlayerInAnyVehicle then if they are, GetPlayerVehicleID and do something. But you may as well just get the vehicle ID on every iteration and just check if it's valid thus only calling one function instead of two that pretty much do the same thing only one returns a normalised result.

Another example of the second point: I am using YSI to develop a higher level player-interaction library, SIF. If I upgrade to YSI 4.0 because I need a feature that is only in YSI 4.0 and y_hooks breaks while Y_Less is on holiday, I am completely stuck as I have no idea how y_hooks works or how to fix it.
I have read the first article: well, it's obvious that abstractions can simplify things but cannot do miracles (like the examples of TCP when a snake chews your network cable or having to drive more slowly when it's raining). Apart from that, the article tells us that we must learn how abstractions work and the things they abstract away, but with that reasoning we sa-mp scripters would have to learn binary code just in case abstraction layers like Pawn start leaking.

I have also read the second article and well, I understand its point in the example of calculating the position of a point from a plane and using two functions when only one was enough, but then, must we know exactly all the internals of every single function from every single abstraction layer we use? progress in hardware, with more and more CPU, memory, graphics and storage resources available, improved energetic efficiency, longer lasting batteries and decreasing prices, should all compensate by far that loss of code optimization brought by the increased number of layers. In fact in that article there's a comment which shows what Y_Less said in this thread: sometimes readable code being better than fully optimized but harder to understand code.
Here in sa-mp scripting we have a clear example with file scripts: Dini is an abstraction layer for sa-mp's raw file functions and it's slower, but much more usable than those. Y_ini is another abstraction layer, and while more optimized than Dini, it's also harder for the scripter.

I think your example about IsPlayerInAnyVehicle and GetPlayerVehicleID, although somewhat similar to that of the article about the point and the plane, has more to do with the scripter not thinking well than with the abstraction layers themselves, because in this case you can easily know that GetPlayerVehicleID itself is enough to tell if a player is in a vehicle.

Your example about upgrading to YSI 4.0 and something breaking, reminds me of a thread I read about sa-mp not upgrading to a newer version of Pawn so some "hacky" things won't stop working.
Reply
#30

SA:MP hasn't upgraded because doing so would break almost every script ever, not just the "hacky" ones. Yes, we have pushed the limits of the current version and upgrading would require some major overhauls in some areas, but when EVERYTHING needs to be changed for a new version it just isn't going to happen and I'm quite glad it isn't!
Reply
#31

Quote:
Originally Posted by ColeMiner
View Post
SA:MP hasn't upgraded because doing so would break almost every script ever, not just the "hacky" ones. Yes, we have pushed the limits of the current version and upgrading would require some major overhauls in some areas, but when EVERYTHING needs to be changed for a new version it just isn't going to happen and I'm quite glad it isn't!
I'm afraid my comment sounded as if I were asking for a Pawn upgrade when actually that wasn't my intention, I'm fine with our current Pawn version.
Reply
#32

I am writing a new gamemode. The gamemode will be MySQL based and I want to separate each 'system' into files. The reason for this is because more developers will be working on the gamemode in the future. I want it so that each developer can work on a particular system at the same time and to also prevent leakage of the gamemode.

Any suggestions?
Reply
#33

All the suggestions are generally, do what you already plan to do. Make sure your interfaces are clean too - keep all variables "static" from the start and let different files interact with each other only through functions, that way you will find that modifying how things work becomes much simpler.

Also, look up y_master if you are concerned about code theft. That allows you to split your separate files up and compile them as filterscripts, so your developers don't have all your source code; but allows you to compile everything in to one single mode with no modifications.
Reply
#34

Quote:
Originally Posted by Y_Less
View Post
All the suggestions are generally, do what you already plan to do. Make sure your interfaces are clean too - keep all variables "static" from the start and let different files interact with each other only through functions, that way you will find that modifying how things work becomes much simpler.

Also, look up y_master if you are concerned about code theft. That allows you to split your separate files up and compile them as filterscripts, so your developers don't have all your source code; but allows you to compile everything in to one single mode with no modifications.
Appreciated. I will look up y_master, thanks.
Reply
#35

Quote:
Originally Posted by Y_Less
View Post
keep all variables "static" from the start
By the way, is it possible for a variable to be both "static" and "stock" at the same time?
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)