PDA

View Full Version : Gamemode Script Layout


MP2
04/07/2012, 08:36 PM
Hei.

I've recently started development of a new gamemode/server and while originally the layout was okay, as it's building up more and more code it seems to be working less.

I have this issue where when I want to script something new, for example let's say I want to script some random weapon pickups - I need three things. The array of data, the creation and the OnPlayerPickUpPickup. First thing I do is the array - but I start to go 'WHERE DO I PUT THE ARRAY DO I PUT IT ABOVE ALL THE OTHERS OR AT THE BOTTOM OR A NEW SECTION FOR WEAPON PICKUPS OR WHAT' and yeah.

This is the current roughly layout of my gamemode (FROM MEMORY):

Includes

Defines

Enums/Arrays

Variables

Callbacks

Custom Functions

mySQL query callbacks

Timers

and I guess that's okay, but I seem to be losing track of where everything is.

Also I split my callbacks up in to sections, so like in OnGameModeInit I would do something like

Initial setup (DisableEnterExits and that sort of thing)
mySQL connection
Objects
Pickups
etc.

So yeah, let's discuss layout options. What do you do? What could I do to improve?
I know some people put different systems in different files and #include them, but I think that'd be a bit of a ballache. Instead of saying 'oh I need to add a new weapon to my weapon pickups, I'll just Ctrl+F and find the array and add it in' you'd have to find out what file it's in, find that file in your /include folder then Ctrl+F through that.

I dunno, it would make it more organized I guess. I'm also developing this server with another person (blewert \o/) and we need a way to contribute to the script at the same time. I guess having systems in separate files then including them would make our lives easier.

KyleSmith
04/07/2012, 08:38 PM
For me, tis:

Includes
Defines
Arrays / Enums
Variables

Then after that anything really, if I had a group chat system I place the stocks near the commands where it's required etc.

Also pop on the IRC and query me please.

Vince
04/07/2012, 09:05 PM
I have kind of the same problem where all variable declarations are scrambled. I try to use static locals(*) where possible, but that doesn't always cut it. I also do include lots of stuff, and in fact I created a whole folder structure for it. I also always seem to code with the thought in mind that I might actually release the script one day and that it thus must be somewhat noob friendly.

At the top of my GM I define general settings like #undef MAX_PLAYERS, #define LOCALHOST and stuff like that, followed by my list of files;


// ================================================== ===========================
// Variable Declarations

#include "../src/def/colors.txt" // Color definitions
#include "../src/def/sound_otb.txt" // Various sound ids
#include "../src/def/forward.txt" // Forward declarations for public functions
#include "../src/def/trucking.txt" // Coordinates for trucking pickup and dropoff
#include "../src/def/bcases.txt" // Coordinates for briefcase locations
#include "../src/def/unsafepass.txt" // List of unsafe passwords (used during registration)
#include "../src/def/var/fishlist.txt" // List of fish and rarity

#include "../src/def/enum/player/flags.txt" // Player boolean values and stock functions
#include "../src/def/enum/player/timers.txt" // Variable to store player timers

#include "../src/def/enum/global/textdraw.txt" // Various general textdraws
#include "../src/def/enum/global/checkpoints.txt" // Checkpoint definitions
#include "../src/def/enum/global/dialogs.txt" // Dialog definitions
#include "../src/def/enum/global/skills.txt" // Skill definitions

#include "../src/func/pinfo.txt" // PlayerInfo enum
#include "../src/func/pstats.txt" // PlayerStats enum
#include "../src/func/hinfo.txt" // HouseInfo enum
#include "../src/func/insurances.txt" // Insurances enum and stock functions

// ================================================== ===========================


which in turn is followed by random variables.

I'll probably clean it up one day. Not now.


(*) Example of static locals:

public OnPlayerUpdate(playerid)
{
if(IsPlayerNPC(playerid)) return 1;

// ----- OnPlayerHealthChange -----
static
Float:oldHealth[MAX_PLAYERS];

GetPlayerHealth(playerid, PlayerStats[playerid][pHealth]);

if(PlayerStats[playerid][pHealth] != oldHealth[playerid])
{
OnPlayerHealthChange(playerid, PlayerStats[playerid][pHealth], oldHealth[playerid]);
oldHealth[playerid] = PlayerStats[playerid][pHealth];
return 1;
}
// -----
return 1;
}

Works absolutely fine.

ReneG
04/07/2012, 10:30 PM
Call me an idiot, but I go for the same layout as the Godfather.


Includes
Defines
Public function forwards
Enums/Arrays
Variables
All default SA-MP callbacks
All custom functions.
Timers
Commands

All SQL code goes into an include file. Weird, but I edit the SQL include with Notepad++, CTRL+S, and compile. Different than using Pawno, and having it all cluttered in your mode.

the_chaoz
05/07/2012, 02:23 AM
Normaly for small scritps I tend to do something like this:
Includes
Macros
Vars/Arrays
Callbacks
(Commands if using ZCMD)
Functions

But on my GM I use includes for each system, so I do it this way:
Includes (#Incldue ""../Data/Systems/System_Name/Header"
Callbacks


Each system include header looks like this:
#include "../Data/Systems/System_Name/Arrays"//includes macros, enums, arrays, variables
#include "../Data/Systems/System_Name/Functions"
#include "../Data/Systems/System_Name/Callbacks"
#include "../Data/Systems/System_Name/Commands"
#include "../Data/Systems/System_Name/Dialogs"

It's quite simple to find bugs or change things from a system.

Y_Less
05/07/2012, 02:41 AM
OK, I'm intrigued, those of you who arrange your code by declaration type instead of function, why do you think this is a good way of doing it? And this is an honest question not sarcasm! The fact that a vehicle enum looks a little bit like a player enum doesn't mean that they're related in any way, so why put them together? That seems to me like organising a library by the colour of the book covers instead of the book topics!

As for having separate directories for systems and separate files for the different declarations in those systems - that's getting closer to a good layout but still means you can't use "static" to restrict access to data. Think of "static" as data private to a system - you want all of the system to be able to see that data, but you don't want any other system to see that data because they could start adjusting it in bad way. Instead you just provide a clean API to interact with that data any everyone is happy.

I'm not sure how this is even someone any programmer should wonder:

Number of major open source projects who "organise" their code in one massive file sorted by keyword: 0
Number of major open source projects who organise their code by splitting code up in to separate chunks of related functionality: All of them!

That alone should tell you something. I really suggest you start reading outside of SA:MP - you might learn something! There is a free book out called "The architecture of open source projects volume 2" - look it up. Also, just any generic reading on any generic programming will VERY quickly get on to how to split up code by function.

Finally, why do you think there are separate includes for player functions and object functions? Do you think that maybe says anything about the internal structure of the server's code? And I'm not giving ANYTHING away by saying that because any programmer with more than 10 minutes experience would realise that a large program like the server would split those functions up in that way.

MP2
05/07/2012, 03:13 AM
The general reason I and others put arrays and enums etc. above callbacks is because (obviously) the callbacks can't use them if they're declared after them. Most of them get used in OnGameModeInit so it wouldn't make sense to have them at the bottom of the script.

For example my weapon pickup array - it needs to be above OnGameModeInit because they get created there.

I do agree splitting up systems is important - I'm just not totally sure how to do it. I'm sort of put off by the fact of having a million files when I could just have one.

Also, say you scripted something 2 years ago and it's in some file in some directory in some other directory - if the compiler gives an error it's going to say the error is in your GM, not which file. How are you meant to remember what file the script is in?

I should also point out I'm co-developing this with another person - which makes it even harder to organize stuff.

I am definately going to split many systems and include them, for example the housing system, ammunation, bank robberies and stuff like that.

[ABK]Antonio
05/07/2012, 03:51 AM
Meh, it doesn't really matter what anyone's opinion on this is aside from your own. Though I'm still going to throw mine out there :P

I organize like Y_Less said no one does. The reason for this...I find it much easier. If I forget the name of the function I just made...variable or anything else - I won't have to search everywhere for it (with "splitting code up in to separate chunks of related functionality" you can lose things very easily. even if they're related).

I do go like most of you...sort of


Includes
Macros
Enums
Arrays
Vars
Main
ongamemodeinit
onplayerconnect
..
onplayerdisconnect
ongamemodeexit
Commands
Custom functions (not publics (those are in a separate place))
Custom functions (publics (not just timers, things for cross server stuff go here too))
Save File stuff (I always put it at the bottom (aside from forwards), just for easier access)
Forwards

I also comment above the beginning of them - keywords. Though I'm not an open source kind of guy.

the_chaoz
05/07/2012, 04:36 AM
OK, I'm intrigued, those of you who arrange your code by declaration type instead of function, why do you think this is a good way of doing it? And this is an honest question not sarcasm! The fact that a vehicle enum looks a little bit like a player enum doesn't mean that they're related in any way, so why put them together? That seems to me like organising a library by the colour of the book covers instead of the book topics!

As for having separate directories for systems and separate files for the different declarations in those systems - that's getting closer to a good layout but still means you can't use "static" to restrict access to data. Think of "static" as data private to a system - you want all of the system to be able to see that data, but you don't want any other system to see that data because they could start adjusting it in bad way. Instead you just provide a clean API to interact with that data any everyone is happy.

I'm not sure how this is even someone any programmer should wonder:

Number of major open source projects who "organise" their code in one massive file sorted by keyword: 0
Number of major open source projects who organise their code by splitting code up in to separate chunks of related functionality: All of them!

That alone should tell you something. I really suggest you start reading outside of SA:MP - you might learn something! There is a free book out called "The architecture of open source projects volume 2" - look it up. Also, just any generic reading on any generic programming will VERY quickly get on to how to split up code by function.

Finally, why do you think there are separate includes for player functions and object functions? Do you think that maybe says anything about the internal structure of the server's code? And I'm not giving ANYTHING away by saying that because any programmer with more than 10 minutes experience would realise that a large program like the server would split those functions up in that way.

Well that's a nice question you got there, but I can only answer for myself and not for others, so here I go.

In small scripts I tend to organize by "types" and not by "topic" as it's much easyer for me to find things, Ex: I got a 2000k lines file, and I need to remember how I did name an enum object, as I have all of them togeter it's a way faster. May you're right, enums may be for players/vehicles/special types but it's like when you (or at least me) organize your books at university/school, I organize them for years, not by each subject (may when I finish it i'll organize them by subject, but not for now).

And about the systems, I do need them go be conected with each other, not all of them but most of them, that's why I do it this way.

Vince
05/07/2012, 07:53 AM
Also, say you scripted something 2 years ago and it's in some file in some directory in some other directory - if the compiler gives an error it's going to say the error is in your GM, not which file. How are you meant to remember what file the script is in?

The compiler actually does tell you what file the error is in.

MadeMan
05/07/2012, 04:58 PM
The layout I'm trying to keep in my scripts:

Includes
Defines
Macros
Variables/Enums
Stock functions
Regular functions
Public functions
Callbacks

Reason: before you can use a variable/function, you need to define it. I find it logical that definitions come before parts that use them. Callbacks use functions, functions use variables and variable definitions require defines (#define).

And it makes searching for definitions easier: go to top of the script (Ctrl + Home), use search (Ctrl + F) and the first result is the definition.

AndreT
07/07/2012, 03:25 PM
What a nice topic to discuss on!

Calling my server a large project would be an exaggeration, but I do follow the same fashion of having separate files. To be more precise, 15 of them. I started doing this in 2010 and I also converted an old mode of mine to use several files.

To whoever this might look difficult to handle... stop using Notepad to script! (or Pawno, quite the equivalent). Use Notepad++ instead, it offers a very convenient way of handling files. And I believe that at least a few of the many plugins assist programmers in creating directory structures even more. Following Slice's tutorial, Notepad++ can also instruct the compiler to compile your code.

The benefits from doing this are immense. A good naming convention for your gamemode files will instantly make you aware of what is where and even with quite a lot of files containing PAWN code, I can still remember the location of certain functions quite well, or at least I have an idea of whether they're positioned in the lower/upper part of the SFSE_*.pwn file. Libraries and methods introduced by Zeex (zcmd) and whoever thought of handling dialogs in a similar way have made things even more convenient, as commands, MySQL result callbacks and much more can be shared between files, so the gamemode is categorized nicely. Writing new code for your mode is easy as well, as the more code unrelated code is in your currently operated file, the more distracted you will most likely get.

And for the record, there's not a problem with getting the location of an error unlike someone pointed out.

So multiple files... good idea!

Finn
07/07/2012, 04:46 PM
I must disagree with you guys about spreading the gamemode into separate files.

I am using 20 includes + couple of filterscripts, so splitting up the code even more would make the gamemode look like it was blown up. I don't have any opinion regarding color defines and shit like that placed in their own files, because I don't really have too many of them laying around.

I like the idea of having "visual code" (aka the gamemode) in 1 single file and the systems which 'run' the gamemode and offer handy functions in their own include files. Also I'm grouping up the code so the related functions, timers, commands and such are in the same section of the gamemode making it very easy to edit the system which is under development or being fixed.

Lorenc_
07/07/2012, 05:49 PM
I just add my core gamemode functions inside its own include.

includes
defines
enums
variables
forwards
main(){}
publics
commands (replaced OnPlayerCommandText with OnPlayerCommandPerformed, so...)
other publics
functions
sql dump at the bottom

ReneG
07/07/2012, 06:01 PM
What a nice topic to discuss on!

Calling my server a large project would be an exaggeration, but I do follow the same fashion of having separate files. To be more precise, 15 of them. I started doing this in 2010 and I also converted an old mode of mine to use several files.

To whoever this might look difficult to handle... stop using Notepad to script! (or Pawno, quite the equivalent). Use Notepad++ instead, it offers a very convenient way of handling files. And I believe that at least a few of the many plugins assist programmers in creating directory structures even more. Following Slice's tutorial, Notepad++ can also instruct the compiler to compile your code.

The benefits from doing this are immense. A good naming convention for your gamemode files will instantly make you aware of what is where and even with quite a lot of files containing PAWN code, I can still remember the location of certain functions quite well, or at least I have an idea of whether they're positioned in the lower/upper part of the SFSE_*.pwn file. Libraries and methods introduced by Zeex (zcmd) and whoever thought of handling dialogs in a similar way have made things even more convenient, as commands, MySQL result callbacks and much more can be shared between files, so the gamemode is categorized nicely. Writing new code for your mode is easy as well, as the more code unrelated code is in your currently operated file, the more distracted you will most likely get.

And for the record, there's not a problem with getting the location of an error unlike someone pointed out.

So multiple files... good idea!
It gets glitchy when you have multiple files open I guess

I was working in an include using notepad++ and had a couple of errors when I compiled. I fixed them and hit ctrl+s to save. Then when I went to Pawno to compile, and it wouldn't recognize that I've updated the include.

Y_Less
07/07/2012, 11:19 PM
It gets glitchy when you have multiple files open I guess

I was working in an include using notepad++ and had a couple of errors when I compiled. I fixed them and hit ctrl+s to save. Then when I went to Pawno to compile, and it wouldn't recognize that I've updated the include.

That has never happened to me ever, in MANY years of coding!

DeathTone
07/07/2012, 11:22 PM
Includes
Defines
Variables
Enums
Callbacks
Public timers
Custom Callbacks
ZCMD Commands
Mysql functions
Stock functions

but it gets EXTREAMLY messy sometimes, too much clutter, so I think i'll just add all my important defines and stocks, central stuff (such as small but important player variables), into one include to make it much easier to read and edit stuff.

MP2
08/07/2012, 01:37 AM
Well I've decided to do a bit of both. I'm still going to have a lot of stuff in the gamemode but some 'systems' will be in files such as the ammunation script. I don't like the idea of having a million files. To me it's like taking 5 shopping lists in to a supermarket - each one has a different 'category' of food or something. It's simpler to just have 1.

JoBullet
08/07/2012, 02:42 AM
Look up PAWN-Boilerplate project by Slice for solid script layout.

MP2
08/07/2012, 02:53 AM
Yeah I know about that.

Simon
08/07/2012, 06:23 AM
I tend to layout gamemode projects by seperating the files into folders. The folders symbolize a library or a 'class' of related methods. The rough idea is as follows:


<mode>.pwn (Link all the modules together, delegate responsibilities to <module>.pwn)
<mode>.h (Define your global constants, enumerations and forward functions. Variables)
version.in (Optional. SVN repository input file, allows for revision numbers to be generated to version.h which <mode>.h can include)
compile.bat (Optional. Runs some extra compiling procedures such as getting SVN revision number and authors)
modules\

modules.def (Optional. Define your scoping definitions here if you like using them, Module1::, Module2:: etc)
<module>\

<module>.h (Define your module constants, enumerations and forward functions. Variables)
<module>.pwn (Your module core logic, written as if it were a library for use by your handler. Variables)
events.pwn (Custom events/callbacks defined by your module. Code is very specific to the gamemode (messages etc.), generally not able to be re-used.)
handlers.pwn (Handle SA:MP and other 'external' callbacks using your module)


scriptfiles\ (List of scriptfiles ready to be dumped on the server)

something.cfg
users.db



The .h files are included before all .pwn files in <mode>.h, <mode>.pwn (your compile file) includes <mode>.h. This resolves any undefined variable issues. You should be very careful with manipulating variables directly and try abstract the problem to a method. Methods do not need to be pre-declared unless they have tags.

Where variables are declared varies on your laziness. Ideally I believe the variables should be static and declared in their <module>.pwn file (to allow more general variable names without conflicts, and to discourage manipulating a variable outside of it's "module logical domain"). Use of static can cause undeclared variable compile errors due to file-level symbol hiding. This can be resolved by using getter/setter type methods (which are better theoretically)

A core module can be created for stuff that is unique to the gamemode or cannot be classified into a general purpose library.

iggy1
08/07/2012, 09:35 AM
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.

eesh
09/07/2012, 05:47 AM
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 :D 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

DiDok
10/07/2012, 11:01 AM
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]
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

Universal
15/07/2012, 03:14 PM
- Includes
- Defines
- Enums
- Variables
- Objects & RemoveBuildingForPlayer
- SA-MP callbacks
- Custom functions
- ZCMD commands

Nicholas.
08/08/2012, 10:39 PM
A friend and I are working on a RP gamemode. How should we properly layout our gamemode that it wouldn't get messy? Should we use separate includes for stocks, defines, variables. etc?

Patrik356b
09/08/2012, 06:36 AM
I like to sort things a bit randomly, separated by categories, like:
General includes
General data
SQL Stuff
GameModeInit/Exit
Commands
Dialogs
Others

At each category I declare only what's relevant.

I have 2 includes for common functions.

[HLF]Southclaw
10/08/2012, 09:28 PM
My gamemode increased massively recently, I added minigames and things.
I'd been playing about with Java and liked the whole 'class' thing (Later discovered to be OOP)

I've had separate files for a while now, I started to fix up my variable names when I had free time watching TV etc, loosely following Hungarian Notation, adding a "context prefix" followed by the standard variable name in H.N.:

races.pwn:
rc_giVehicleID
rc_giPlayerCount
rc_gtick_Start
rc_gflag_State
deathmatch.pwn:
dm_bSettings
dm_iCountdownValue
dm_Map
dm_Mode
I added a few prefixes like:
'tick' a tick counter, always used with GetTickCount for stopwatches etc
'flag' a flag with multiple values, such as the state the race can be in (Counting in, started, stopped, inactive, waiting for players etc)

'b' bit array, I used to use it for booleans but I don't use them anymore, it's all in bit arrays.
'g' global, as standard
'p' player related
'v' vehicle related
'o' object related

's' string (I ignore that 'sz' zero terminated thing, that doesn't apply in Pawn right?)
'i' integer
'f' float
'a' array followed by one of the above 3

As for structure, all things are declared/defined in their respective files unless used in multiple files, in which case they are declared in a 'public' area in the main script.

The (bad) structure:


Comments and credits in case I ever release my script (technically it is, I just never update the repo)
Main inckudes from "pawno/include"
Definitions/macros and shit, really unorganised section...
server related things like notification messages, admin-rank-names, bit settings, weather enum/variable, all that jazz...
'public' declarations, for stuff used in multiple scripts (even though it aint all here)
player related things like main data enumerator, bit array
vehicle things (not many of them)
the other includes from "../scripts" (included after the declarations and not with the other includes because of global stuff)
main()
massive clusterfuck of callbacks in no particular order (connect, class things, login, disconnect, logout, player input)


I can't believe I spend this long, I must have a lot of free time...

Anyway, it's certainly not a perfect system and needs a lot of refining! I have my old self to blame, stupid variable names etc but we live and learn! :p

Dan..
11/08/2012, 06:28 PM
Hello!

I've been scripting a game mode in Pawno for about 2 weeks, but most of the time I spent on the design of the server.

My first try was to write a very-very-long script in only one file. I reached almost 2000 lines, includes, variables, methods, commands all mixed in there so I tried something else. It was to messy for my taste.

At my second try I tried writing a "merger" that would automatically merge multiple files, declare function prototypes and arrange them in a such order so the output could be compiled by pawncc. I found that way cleaner as I could arrange my functions and engines in separate folders and files. However, that isn't pleasent enough as there are still some stuff mixed.

The third way, I was planning to use hooks and different files (something like some mini-gamemodes) that would merge togheter and make the final gamemode. However, this way seemed a bit unstable and not very efficient.

Currently, I'm looking for a fourth way to make it even more readable: each "engine" in a filterscript, but I still have to work a way to make variables global (so they can be accessed by all filterscripts). There would be lots of advantages, one of the most important being that you can reload parts of your server without any troubl and lots more.

Do you have any ideas how can I achieve that? (I guess I'll have to work on a plugin or use AMX properties - a way I don't really like.)

How do you manage your server?

I'm looking forward to hear your great ides.

Bakr
12/08/2012, 05:02 AM
Currently, I'm looking for a fourth way to make it even more readable: each "engine" in a filterscript, but I still have to work a way to make variables global (so they can be accessed by all filterscripts). There would be lots of advantages, one of the most important being that you can reload parts of your server without any troubl and lots more.

Do you have any ideas how can I achieve that? (I guess I'll have to work on a plugin or use AMX properties - a way I don't really like.)

Using filterscripts to reload certain parts of your script is a very nice idea. As for your question, you can use the PVar functions (example: http://wiki.sa-mp.com/wiki/SetPVarInt) and property functions (example: http://wiki.sa-mp.com/wiki/setproperty) to communicate between filterscripts and the main gamemode script.

After reading through the posts in this thread, I really like Simon's approach. Separating core concepts of the mode into different files is a nice idea while having a main core to tie everything together. I will definitely be using this approach in my next project.

Dan..
12/08/2012, 07:41 AM
Using filterscripts to reload certain parts of your script is a very nice idea. As for your question, you can use the PVar functions (example: http://wiki.sa-mp.com/wiki/SetPVarInt) and property functions (example: http://wiki.sa-mp.com/wiki/setproperty) to communicate between filterscripts and the main gamemode script.

After reading through the posts in this thread, I really like Simon's approach. Separating core concepts of the mode into different files is a nice idea while having a main core to tie everything together. I will definitely be using this approach in my next project.

Simon's approach is the equivalent of a mixture of my second and third approach and it isn't such a good one as it looks like.

Each "package" is in fact a "mini-gamemode". Every callback defined is actually a hook and the number of these hooks would be big. Let's say we have 20 jobs with almost 3 events each (there will be more for sure). You'll have to use 60 hooks, which in my opinion isn't that good. Also, the variables would still be mixed.

In my opinion, the filterscripts-approach is the best, but we need to find a way to declare "global" variables and functions. I don't think is a good idea using AMX properties. They aren't fast enough.

L.E. This is my layout at this moment: https://dl.dropbox.com/u/8087080/ShareX/2012-08/2012-08-12_11-20-20.png

Y_Less
12/08/2012, 08:58 AM
Dan: look up y_master, it does multi-script functions very smoothly. Not variables though, but frankly globals are bad, you should just be using functions to access different script modules, variables hold internal data which can change without warning.

What you describe with different engines in different scrips is exactly what y_master was designed for. However, I'd like to know why you think hooks are bad - they are actually now very fast and easy to use.

Dan..
12/08/2012, 06:03 PM
Dan: look up y_master, it does multi-script functions very smoothly. Not variables though, but frankly globals are bad, you should just be using functions to access different script modules, variables hold internal data which can change without warning.

What you describe with different engines in different scrips is exactly what y_master was designed for. However, I'd like to know why you think hooks are bad - they are actually now very fast and easy to use.

I've checked up y_hooks. I thought they were slow just because of the complexity, but it seems you have optimised those hooks a lot. They are very fast and I think I'm going to work with them in my future projects. About y_master, well.. as far as I've got the hooks-method I won't need it. Also, I already said that global variables would be a pain in the ass and also would be slow, unless you come with a nice idea.

Y_Less
12/08/2012, 06:59 PM
I do have an idea for true globals as it is possible to read arbitrary memory addresses. IF you can find the address of some variable in another script then you can use reduced code to read it (but still more than just reading one script local global). That I think will be the fastest way, but I'm still working on how to make it happen.

Dan..
12/08/2012, 08:25 PM
I do have an idea for true globals as it is possible to read arbitrary memory addresses. IF you can find the address of some variable in another script then you can use reduced code to read it (but still more than just reading one script local global). That I think will be the fastest way, but I'm still working on how to make it happen.

That's what I was thinking too, but you'll still have to find those addresses of variables in each script loaded.

Y_Less
12/08/2012, 09:59 PM
Yes, but that's actually the easy part!

Dan..
13/08/2012, 06:18 AM
Yes, but that's actually the easy part!

If I'm not mistaken y_amx does that for you, right?

Y_Less
13/08/2012, 07:27 AM
Yeah, or there is functionality that you can use in there.

im
13/08/2012, 09:45 AM
I use one big .pwn file with not-so-organized code and 20k+ lines of code.. I have to CTRL+F when I'm looking for something anyway, so it doesn't really matter if I have the functions organized by type or just put in a random order..

I tried using multiple files for my gamemode, but that didn't work for me. It's kinda hard to use multiple files and there are not enough examples on the forum on how to do that. All the gamemodes in the gamemodes section use just one big .pwn file.

Westingham
13/08/2012, 12:54 PM
If I were trying to streamline my gamemode, would it better to put some common code that I'm going to use over and over into an include or into a filterscript?

Related: what is the difference between an include and a filterscript and are there advantages to using one over the other?

Y_Less
13/08/2012, 12:58 PM
I use one big .pwn file with not-so-organized code and 20k+ lines of code.. I have to CTRL+F when I'm looking for something anyway, so it doesn't really matter if I have the functions organized by type or just put in a random order..

Have you considered that if it was ordered you wouldn't need to search as much as all the functions related to the one you were currently working on would be within scroll distance?

[HLF]Southclaw
13/08/2012, 01:48 PM
It's kinda hard to use multiple files and there are not enough examples on the forum on how to do that. All the gamemodes in the gamemodes section use just one big .pwn file.

It's exactly the same as how you use #include <scriptname> that basically just takes all the code from that file, and inserts it at the point you write the include line.

using <scriptname> will automatically read from the "pawno/includes" folder, but you can use "scriptname" to read straight from the same folder as the gamemode script (I think, correct me of I'm wrong!)

You can also use "../" to go 'up' a folder, so if I wrote this:

#include "../scripts/MyScript.pwn"

it would go up from the folder the gamemodes is in (In my case, my main SA:MP server folder) then go into a folder in there called 'scripts' and open "MyScript.pwn".



There are some more interesting things about #include I think, I can't remember though!




If I were trying to streamline my gamemode, would it better to put some common code that I'm going to use over and over into an include or into a filterscript?

Related: what is the difference between an include and a filterscript and are there advantages to using one over the other?


Filterscripts are loaded separately, includes are basically just bits of the main gamemode in separate files.

For instance, I could have an OnPlayerUpdate in a filterscript and one in a gamemode, they would be called separately, you wouldn't have any problem.

But if I had OnPlayerUpdate| in a gamemode/filterscript and in a file I was including into that gamemode/filterscript, I would get a "Symbol already defined error" because it's the same as defining OnPlayerUpdate twice in one script.

Gryphus One
13/08/2012, 02:33 PM
Dan: look up y_master, it does multi-script functions very smoothly. Not variables though, but frankly globals are bad, you should just be using functions to access different script modules, variables hold internal data which can change without warning.

What you describe with different engines in different scrips is exactly what y_master was designed for. However, I'd like to know why you think hooks are bad - they are actually now very fast and easy to use.

Maybe it's because I'm a scripting beginner, but I don't understand the part that I highlighted in bold: how can variables and arrays change themselves?
This worries me because I'm trying to create my first gamemode by leaving the .pwn file almost empty and writing everything in different includes with callback hooks, and as some of the custom functions that I have created and that are in different includes are called in the same callbacks and would use the same native functions (for example, I have several custom functions that are called in OnPlayerUpdate and would use GetPlayerPos), what I'm doing is first creating an "information" include with global arrays (for example, globalx[MAX_PLAYERS], globaly[MAX_PLAYERS] and globalz[MAX_PLAYERS]), so I use GetPlayerPos in OnPlayerUpdate only in that include to write in those arrays, and in the rest of my functions that are in my other includes I just read those arrays to avoid redundant calls to GetPlayerPos over and over again. And same with several other functions for other kinds of data, like facing angle, velocity, armed weapon, player state, player name, health and armour, vehicle health, etc.
Is this bad?

Y_Less
13/08/2012, 02:47 PM
OK, there are multiple questions here:

Maybe it's because I'm a scripting beginner, but I don't understand the part that I highlighted in bold: how can variables and arrays change themselves?

My post was poorly worded sorry. I meant that if you have an include with a variable called "gSomeData" and it stores some data then you can use it in your script. However, if the person who made the include decides to change how the include works, they may get rid of the "gSomeData" variable and replace it with another one - breaking your code as well. However, if they have written a function like "GetSomeData", then they may change how the function works, but the function itself should remain the same so you can still call it. This is even the case with your own code - you may decide to rewrite one file and as a result have to update every other file when you change the internal structure. If, however, you have a fixed API to access that file (i.e. a fixed list of functions) then it doesn't matter how the implementation changes, it won't change the rest of your code.

This worries me because I'm trying to create my first gamemode by leaving the .pwn file almost empty and writing everything in different includes with callback hooks, and as some of the custom functions that I have created and that are in different includes are called in the same callbacks and would use the same native functions (for example, I have several custom functions that are called in OnPlayerUpdate and would use GetPlayerPos), what I'm doing is first creating an "information" include with global arrays (for example, globalx[MAX_PLAYERS], globaly[MAX_PLAYERS] and globalz[MAX_PLAYERS]), so I use GetPlayerPos in OnPlayerUpdate only in that include to write in those arrays, and in the rest of my functions that are in my other includes I just read those arrays to avoid redundant calls to GetPlayerPos over and over again. And same with several other functions for other kinds of data, like facing angle, velocity, armed weapon, player state, player name, health and armour, vehicle health, etc.
Is this bad?

Yes, that's IMHO a terrible way of doing things, but not because the variables might change. For one, you don't need to store every player's positions all the time, secondly you could just use this and avoid globals:


public OnPlayerUpdate(playerid)
{
new Float:x, Float:y, Float:z;
GetPlayerPos(playerid, x, y, z);
OnPlayerUpdate_1(playerid, x, y, z);
OnPlayerUpdate_2(playerid, x, y, z);
OnPlayerUpdate_3(playerid, x, y, z);
}


Or you could just accept that calling a single native two or three times isn't actually that bad!

Gryphus One
13/08/2012, 03:05 PM
public OnPlayerUpdate(playerid)
{
new Float:x, Float:y, Float:z;
GetPlayerPos(playerid, x, y, z);
OnPlayerUpdate_1(playerid, x, y, z);
OnPlayerUpdate_2(playerid, x, y, z);
OnPlayerUpdate_3(playerid, x, y, z);
}


And using this, would I have to create as many custom OnPlayerUpdate_ callbacks as custom functions I have that are called there?

Y_Less
13/08/2012, 03:06 PM
Well you said you were already hooking them so I'm assuming you already have multiple custom OnPlayerUpdate functions.

Gryphus One
13/08/2012, 03:45 PM
Hmm I'm getting lost. Those OnPlayerUpdate_1(playerid, x, y, z), OnPlayerUpdate_2(playerid, x, y, z) and OnPlayerUpdate_3(playerid, x, y, z) are hooked callbacks, or what are they?

In any case, what's so bad about my method of using global arrays to store all the information of the player? at first glance it might look quite memory consuming, however I use the following reasoning: imagine that instead of using multiple includes, I were writing all my script in the .pwn file, so there would be no callback hooks. Now imagine that, like before, I have several custom functions that check the position of the player and are called in OnPlayerUpdate. In such a case, I would be using local variables inside OnPlayerUpdate to pass that information to those functions. If my server were having a good number of players, all of them sending updates at the same time, the number of those local variables would be proportional to the number of players, so wouldn't all those local variables take up almost the same amount of memory as my global arrays? Just a question, not trying to defend my model at all costs.

EDIT: ups, now that I realize it, even if several players send an update at the same time, the server will process them one after another and not at the same time, and those local variables are destroyed when a callback is finished, and are created again when the callback is called again, so there will be always only one local variable of each type at the same time, and therefore those locals won't take up as much memory, right?

Y_Less
13/08/2012, 05:05 PM
You are right about single-threaded processing, yes.

Gryphus One
13/08/2012, 05:24 PM
Ok thanks for all that information, you really saved my script from being a true memory guzzler.

mastermax7777
25/02/2013, 05:10 AM
i just define everything before each function :D so... no layout its the best ..
im too lazy to sort everything out, takes too much time.. ull get it when u can script like baws like me lolz

im
30/04/2013, 06:34 AM
So, if you use multiple files, some callbacks will be used by more than one module, so with a single files you would have something like this:


public OnPlayerDeath(playerid, killerid, reason){
if(IsACop(killerid)){
SendToJail(playerid);
}
else if(IsAHitman(killerid)){
GiveMoney(killerid, 3000);
}
else if(IsAdmin(playerid)){
BanEx(playerid, "you're not allowed to kill admins");
}
}


In multiple files, you would have to do something like this:

OnPlayerDeath(playerid, killerid, reason){
CopSystemOnPlayerDeath(playerid, killerid, reason);
HitmanSystemOnPlayerDeath(playerid, killerid, reason);
AdminSystemOnPlayerDeath(playerid, killerid, reason);
}


And then in /inc/cop.inc

stock CopSystemOnPlayerDeath(playerid, killerid, reason){
if(IsACop(killerid)){
SendToJail(playerid);
}
}


Isn't it faster to use a single file?

[uL]Pottus
30/04/2013, 06:38 AM
Using a single file gets really messy I don't know about you but when a callback extends for thousands of lines with a dozen different systems integrated it's such a pain in the ass to work with it's not worth doing it that way.

MP2
30/04/2013, 08:23 AM
I'm using a proper file system now, but it's fucking annoying that I can't Ctrl+F for stuff, and Windows 7 is fabulous and doesn't search my file contents (even though in search settings it's set to..).

cessil
30/04/2013, 08:56 AM
In multiple files, you would have to do something like this:

OnPlayerDeath(playerid, killerid, reason){
CopSystemOnPlayerDeath(playerid, killerid, reason);
HitmanSystemOnPlayerDeath(playerid, killerid, reason);
AdminSystemOnPlayerDeath(playerid, killerid, reason);
}


And then in /inc/cop.inc

stock CopSystemOnPlayerDeath(playerid, killerid, reason){
if(IsACop(killerid)){
SendToJail(playerid);
}
}


Isn't it faster to use a single file?

There's many different ways to go about it, if you think about creating a small script per include, something that allows you to become a cop in one, and also include a way to detect if someone was a cop.


stock isACop(playerid)
{
return g_isACop[playerid];
}

cmd:makemecop(playerid,params)
{
g_isACop[playerid] = true;
}

now in your main script you could just use the stocks that you created in the cop include



stock OnPlayerDeath(playerid, killerid, reason){
if(IsACop(killerid)){
SendToJail(playerid);
}
}


so instead of processing everything through all the includes you could just do it in the main pwn file, and use the includes for adding everything needed to be a cop or to be a hitman

MP2
30/04/2013, 08:57 AM
Or hook.

Rajat_Pawar
30/04/2013, 09:00 AM
For me, code optimisation is important, I don't care about the layout honestly, even though it could be bad practice, . I group variable declarations together and that's it. Everything else is messed up, I put new code where I see blank space!

Dan..
30/04/2013, 11:08 AM
I put new code where I see blank space!

That's a good example of bad organization.

In my opinion, the speed and the design of the code should be balanced.

im
02/05/2013, 07:38 PM
I just thought about something. If I were to use hook OnPlayerDeath in 20 include files would that affect the performance in any way? Using hooks would make everyting a lot more organised and readable.

Y_Less
02/05/2013, 07:47 PM
Not really, in fact the next version of y_hooks is improved to the point of being faster to use hooks than not to use hooks!

Dan..
02/05/2013, 08:14 PM
Not really, in fact the next version of y_hooks is improved to the point of being faster to use hooks than not to use hooks!

How can be that even possible? :o

Y_Less
02/05/2013, 08:21 PM
I removed the code that pushes and removes arguments from the stack, so they're pushed once - multiple hooks are called, then all removed at once too. I've written a very detailed post about it here:

http://forum.sa-mp.com/showpost.php?p=2490142