-
Notifications
You must be signed in to change notification settings - Fork 0
Environment Setup
This page covers how to get your development environment set up using sampctl and how to structure your project folders and files.
If you don't already have a dedicated workspace for your SA:MP/open.mp-related projects, I strongly recommend you make one, something along the lines of C:/Users/<username>/PawnProjects. It's common practice anyway and keeps everything clean and organized.
Inside your workspace directory, create a new folder for your new project, like my-awesome-gamemode. Then open your Visual Studio Code Editor and open your project folder such that it appears on the left-hand side. Right now, there is nothing in there but that's going to change soon.
Once you have created your project folder, use the command line to navigate to it (cd <path>) and initialize a new sampctl package using the following command:
sampctl package init
This runs you through a setup wizard for your project. It should look something like this:
Preferred package format json
Your Name - If you plan to release, must be your GitHub username. <your-github-username>
Package Name - If you plan to release, must be the GitHub project name. <project-name>
Add a .gitignore and .gitattributes files? Yes
Add a README.md file? Yes
Select your text editor vscode
Add standard library dependency? Yes
Scan for dependencies? Yes
Initialise a git repository? Yes
Add a .travis.yml for unit testing? No
No .pwn or .inc files - enter name for new script main.pwn
You'll see sampctl spitting out stuff into the console log. This is the package manager making sure all necessary dependencies for SA:MP are downloaded. Also, you'll notice that your project folder isn't empty anymore:
<project-folder>/
├── .vscode/
├── utils/
├── .gitattributes
├── .gitignore
├── pawn.json
└── README.md
You don't need to care too much about what each and every one of these files/folders mean. The folder structure will be covered a bit later on.
You might remember when we initialized our package, sampctl asked us to enter a script name at the very end which is main.pwn for us. This is your entry script. Now, what is an entry script you might ask.
In order to understand why we need an entry script, it's important to understand that standalone libraries, or "includes", cannot be compiled on their own. They need to be embedded into a script that can actually be run, or to be more precise, a script that contains the main() {} game loop.
So, an entry script is the script that contains the main game loop and includes all of the modules in one place so they can be compiled together. A bare-bones entry script looks like this:
#include <a_samp> // Includes all of SA:MP's natives.
main() {} // The main game loop that makes the server a runnable program.Create a main.pwn in the root directory of your project with the contents above and you're ready to move on.
Now, let's explore how you should organize your project folders and files. Go ahead and create the following folder structure:
<project-folder>
├── .vscode/
├── config/
├── dependencies/
├── filterscripts/
├── gamemodes/
├── libs/
├── modules/
├── plugins/
├── scriptfiles/
└── utils/
-
config/contains global definitions/constants to be used gamemode-wide, i.e. a list of colors with their respective color codes inside of acolors.pwnor cardinal directions inside of acardinal_dir.pwn. -
dependencies/contains dependency folders which are managed by sampctl. Do not touch anything in here. If you, for example, want to use the streamer, you simply let sampctl handle it for you by passing the commandsampctl package install samp-incognito/samp-streamer-plugin:v2.9.4into the command line. -
filterscripts/contains filterscripts. Check out the sampctl documentation on how to add filterscripts to your gamemode. -
gamemodes/contains the entry script of your gamemode. -
libs/contains all non-sampctl ("legacy") libraries. -
modules/contains all modules of the gamemode. -
plugins/contains all non-sampctl plugins. -
scriptfiles/contains files specifically required by non-sampctl plugins. -
utils/contains utility/helper functions as well as hooked functions, i.e. astrings.pwnfor common string manipulation or ahooks.pwnwith a hooked SetPlayerHealth native.
Don't forget to move your existing main.pwn entry script into the gamemodes folder where it belongs!
This change also needs to be reflected in the pawn.json which contains an array of configuration settings. Open it and change the value (right side) of the "entry" field to "gamemodes/main.pwn" and the value of the "output" field to "gamemodes/main.amx". You'll end up with a pawn.json like this:
{
"user": "<your-github-username>",
"repo": "<project-name>",
"entry": "gamemodes/main.pwn",
"output": "gamemodes/main.amx",
"dependencies": [
"sampctl/samp-stdlib"
]
}Now that we've established a folder structure and determined where certain files belong, we need to take a closer look at the order in which all of these .pwn files are included such that...
- the compiler doesn't need to reparse for functions used ahead of declaration and
- modules can be included in any order.
Here's the order in which you should include your files in your entry script main.pwn:
- SA-MP natives (
a_samp) - Configuration (
#defines) - Utilities (Hooked functions/natives, utility and helper functions)
- Dependencies (Third-party libraries downloaded via sampctl, like
streamer) - Custom libraries (Your own non-sampctl libraries)
- Modules (
<module>.pwn) - Main game loop (
main() {})
In order to be able to write modules as conveniently as possible, we need to introduce one dependency that is absolutely mandatory - y_hooks which is part of Y-Less's YSI Framework. It allows us to hook functions and callbacks while avoiding all the visual clutter associated with classic ALS hooking.
Download the YSI 5.x library using the following command:
sampctl package install pawn-lang/YSI-Includes@5.x
Once it is downloaded, go ahead and include YSI_Coding\y_hooks into your entry script. It should look something like this:
#include <a_samp>
// Configuration
// Utilities
// Dependencies
#include <YSI_Coding\y_hooks>
// Custom libraries
// Modules
main() {}You may have noticed that your pawn.json also got updated after downloading the YSI Framework. You'll find a new "runtime" object which is basically a JSON-version of the server.cfg file.
One more object we'll need is the "build" object in which we specify the folder for custom libraries (includes in the libs/ folder) and set some of our global compile-time constants like the MAX_PLAYERS value and feature toggles for YSI in the nested "constants" object.
The last thing we'll need to do is add the "local" entry in our root object and set it to true in order to run the package in our local directory.
Your pawn.json should now look something like this:
{
"user": "<your-github-username>",
"repo": "<project-name>",
"entry": "gamemodes/main.pwn",
"output": "gamemodes/main.amx",
"local": true,
"dependencies": [
"sampctl/samp-stdlib",
"pawn-lang/YSI-Includes@5.x"
],
"build": {
"includes": ["libs"],
"constants": {
"MAX_PLAYERS": "<maxplayers>",
"YSI_NO_OPTIMISATION_MESSAGE": "",
"YSI_NO_VERSION_CHECK": ""
}
},
"runtime": {
"version": "0.3.7",
"mode": "<servermode>",
"echo": "-",
"rcon_password": "<password>",
"port": 7777,
"hostname": "<hostname>",
"maxplayers": "<playerslots>",
"filterscripts": [],
"language": "",
"mapname": "San Andreas",
"weburl": "<website>",
"gamemodetext": "<gamemodetext>",
"announce": true,
"lanmode": false,
"query": true,
"rcon": false,
"logqueries": false,
"sleep": 5,
"maxnpc": 0,
"stream_rate": 1000,
"stream_distance": 200,
"onfoot_rate": 30,
"incar_rate": 30,
"weapon_rate": 30,
"chatlogging": true,
"timestamp": true,
"messageholelimit": 3000,
"messageslimit": 500,
"ackslimit": 3000,
"playertimeout": 10000,
"minconnectiontime": 0,
"lagcompmode": 1,
"connseedtime": 300000,
"db_logging": false,
"db_log_queries": false,
"conncookies": true,
"cookielogging": false,
"output": true
}
}