Jump to content

[C++] Cum sa creezi un mod de tip SFPlugin


MAMRETRAS
 Share

Recommended Posts

Hello guys. De la o vreme tot vad ca apar moduri CLEO, which is bad. Exista foarte multe limitari la nivel de limbaj. In cele ce urmeaza, va voi arata cum sa create moduri de tip SF Plugin, dintr-acelea pentru SAMPFUNCS.

 

Inainte de toate, asigurati-va ca aveti descarcat:

  • Visual Studio cu pachetul MSVC v140 (Visual Studio 2015 il are direct, pentru versiunile noi, trebuie adaugat). Eu unul folosesc MSVC v141 Visual Studio 2017 toolset pentru Windows XP. Le incercati pe amandoua.
  • SAMPFUNCS TEMPLATE: click. Dezarhivati arhiva. Modurile create se vor afla in SF Plugins > Release.
  • Windows SDK si DirectX9 SDK.

 

Dupa ce ati instalat mediul de lucru deschideti SF Plugin.sln si intrati in main.cpp. Aici este codul pe baza caruia va veti construi modul.

 

Codul de baza este urmatorul:

 

#include <Windows.h>
#include "main.h"

SAMPFUNCS *SF = new SAMPFUNCS();

void __stdcall mainloop()
{
	static bool initialized = false;
	if (!initialized)
	{
		if (GAME && GAME->GetSystemState() == eSystemState::GS_PLAYING_GAME && SF->getSAMP()->IsInitialized())
		{
			initialized = true;
			SF->getSAMP()->getChat()->AddChatMessage(D3DCOLOR_XRGB(0, 0xAA, 0), "SAMPFUNCS Plugin loaded.");
		}
	}
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReasonForCall, LPVOID lpReserved)
{
	if (dwReasonForCall == DLL_PROCESS_ATTACH)
		SF->initPlugin(mainloop, hModule);
	return TRUE;
}

In interiorul celui de-al doilea if se scrie codul ce se doreste procesat o singura data, dupa ce modul a fost incarcat cu succes (cand se porneste GTA-ul de obicei).

 

FUNCTIE MESAJ INFORMATIV

Cu ajutorul acestei functii:

SF->getSAMP()->getChat()->AddChatMessage(color, text);

Se poate scrie un mesaj pe chat pe care-l vede doar cel care are modul. De obicei, aceasta functie este folosita pentru a trimite mesaje de tip info catre utilizatori. De exemplu:

SF->getSAMP()->getChat()->AddChatMessage(0xFFA500, "[News Reporters Helper] {FFFFFF}Modul a fost incarcat cu succes. Made by {FF0000}Vesca{FFFFFF}.");

 

FUNCTIE SAY PE SERVER

Cu ajutorul acestei functii:

SF->getSAMP()->getPlayers()->pLocalPlayer->Say(text);

Se poate scrie un mesaj direct in joc, care ajunge la server (cu aceasta functie se pot folosi comenzi in-game). De exemplu:

SF->getSAMP()->getPlayers()->pLocalPlayer->Say("/l Buna ziua B-Zone si bine v-am gasit la un nou interviu.");

 

CONSTRUIREA DE COMENZI CUSTOM

Cu ajutorul acestei functii:

SF->getSAMP()->registerChatCommand(command, callback_function);

Se poate construi o comanda in joc [/command]. De exemplu:

SF->getSAMP()->registerChatCommand("sal", sal);

In joc, cand este scris in chat [/sal], pluginul va executa codul din functia "callback_function", in cazul nostru "sal", asadar, trebuie sa aveti si urmatoarea functie in cod:

void CALLBACK sal(std::string params) {
	// instructiuni de executat
}

Pentru exemplul nostru, functia arata cam asa:

void CALLBACK sal(std::string params) {
	SF->getSAMP()->getPlayers()->pLocalPlayer->Say("Salut.");
}

Astfel incat cand in joc scrii [/sal] va aparea pe chat "Salut.":

image.png.48d87f4262a5559230872df1cc6883c7.png

 

De asemenea, functia poate lua parametrii, de exemplu vrei sa saluti un anumit ID: [/sal 24]! Acest lucru este posibil folosind parametrul functiei: "std::string params":

void CALLBACK sal(std::string params) {
	int id = std::stoi(params); // <- transformam din string in int

	if (SF->getSAMP()->getPlayers()->IsPlayerDefined(id)) { // <- verificam daca jucatorul este online
		std::string name = SF->getSAMP()->getPlayers()->GetPlayerName(id); // <- daca este, ii luam numele

		std::string mesaj = "Salut, " + name + "!"; // <- creem mesajul de salut

		char* mesaj_char = new char[mesaj.size() + 1]; // <- il convertim la char
		strcpy(mesaj_char, mesaj.c_str());

		SF->getSAMP()->getPlayers()->pLocalPlayer->Say(mesaj_char); // <- si il salutam
		free(mesaj_char); // <- dupa care eliberam memoria folosita
	}
	else { // <- daca jucatorul nu este online
		SF->getSAMP()->getChat()->AddChatMessage(0xFFA500, "Jucatorul cu ID-ul respectiv nu este ONLINE!"); // <- afisam un mesaj corespunzator
	}
}

image.png.1e5a5084d35c1fb9ff063c2bfef5b857.png

 

Cam asa arata tot codul:

#include <Windows.h>
#include "main.h"

SAMPFUNCS *SF = new SAMPFUNCS();

void CALLBACK sal(std::string params) {
	int id = std::stoi(params); // <- transformam din string in int

	if (SF->getSAMP()->getPlayers()->IsPlayerDefined(id)) { // <- verificam daca jucatorul este online
		std::string name = SF->getSAMP()->getPlayers()->GetPlayerName(id); // <- daca este, ii luam numele

		std::string mesaj = "Salut, " + name + "!"; // <- creem mesajul de salut

		char* mesaj_char = new char[mesaj.size() + 1]; // <- il convertim la char
		strcpy(mesaj_char, mesaj.c_str());

		SF->getSAMP()->getPlayers()->pLocalPlayer->Say(mesaj_char); // <- si il salutam
		free(mesaj_char); // <- dupa care eliberam memoria folosita
	}
	else { // <- daca jucatorul nu este online
		SF->getSAMP()->getChat()->AddChatMessage(0xFFA500, "Jucatorul cu ID-ul respectiv nu este ONLINE!"); // <- afisam un mesaj corespunzator
	}
}

void __stdcall mainloop()
{
	static bool initialized = false;
	if (!initialized)
	{
		if (GAME && GAME->GetSystemState() == eSystemState::GS_PLAYING_GAME && SF->getSAMP()->IsInitialized())
		{
			initialized = true;
			SF->getSAMP()->getChat()->AddChatMessage(0xFFA500, "Salut Plugin loaded.");
			SF->getSAMP()->registerChatCommand("sal", sal);
		}
	}
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReasonForCall, LPVOID lpReserved)
{
	if (dwReasonForCall == DLL_PROCESS_ATTACH)
		SF->initPlugin(mainloop, hModule);
	return TRUE;
}

Daca apar intrebari, va astept cu un PM sau reply la acest topic.

Edited by Vesca
Link to comment
Share on other sites

19 minutes ago, MiHaY111 BahaosFAMILY said:

din cate se pare e mai complicat si mai mult de scris, poate de aia sunt atatea cleo, oricum gg pt tutorial

Mai mult de scris, dar mai usor. In plus, nu ai limitari asa multe cum ai in CLEO.

Link to comment
Share on other sites

4 hours ago, Madalin said:

Dacă ne-ai spune şi cum decompilăm unul :D

Nu ai cum, doar să vezi prin părți ce face programul cutare, dar sursa nu o poți recupera. 

Asta se poate doar in C# :) 

 

O altă variantă în loc de:

std::string mesaj = "Salut, " + name + "!"; // <- creem mesajul de salut
char* mesaj_char = new char[mesaj.size() + 1]; // <- il convertim la char
strcpy(mesaj_char, mesaj.c_str());

 

Ar mai fi:

char* myChar = new char[256];
snprintf(
    myChar, 256,
    "Jucatorul cu ID-ul %d are numele %s",
    Player_ID,
    SF->getSAMP()->getPlayers()->GetPlayerName(Player_ID)
);

 

P.S: Pentru cei care primesc eroare cum că nu se găsește Windows.h, trebuie să dați retarget la proiect.

image.png.35d8aea7c00670f241489ff7b01a5523.png 

 

și să-l upgradați la o versiune nouă (eu folosesc v142 2017).

Edited by shanker'
Link to comment
Share on other sites

5 hours ago, Madalin said:

Dacă ne-ai spune şi cum decompilăm unul :D

Ah, e simplu.

 

Mergi la 2 facultati de informatica pe sectii diferite si te asiguri ca ai cursuri de Reverse Engineer. Dupa care, folosesti niste tooluri avansate care trebuiesc platite doar ca sa vezi un cod pe care daca ai fost la liceu de informatica sau te-ai documentat singur pe acasa il scrii in 10 de minute, fara sa treci prin toate cele spuse de catre mine.

 

1 hour ago, shanker' said:

P.S: Pentru cei care primesc eroare cum că nu se găsește Windows.h, trebuie să dați retarget la proiect.

Sau asa :)) Eu am zis direct cum l-am setupuit eu. Probabil pe v142 sa nu mearga modurile create celor cu Win XP, trebuie verificat.

Link to comment
Share on other sites

21 hours ago, shanker' said:

Cum se ia playerScore?

int player_id = 510;
int player_score;
if (SF->getSAMP()->getPlayers()->IsPlayerDefined(player_id)) // daca jucatorul este conectat
	player_score = SF->getSAMP()->getPlayers()->pRemotePlayer[player_id]->iScore; // salvam "score"-ul, in cazul B-Zone, acesta reprezinta nivelul

 

Link to comment
Share on other sites

@Vesca,

 

dă edit la topic și într-un spoiler să pui toate funcțiile API-ului cerute (inclusiv asta de mai sus)

 

Am nevoie de:

1) ForAllPeds (direct din stActorPool)

2) isActorDefined (a.k.a streamed) (dacă găseam asta, știam să fac și eu func. 1), dar era ineficientă așa :)))

3) ActorCurrentCar sau playerCurrentCar (pHandle / playerID)

4) ForAllVehicles (direct din stVehiclePool) 

 

momentan doar atât :)) 

Link to comment
Share on other sites

On 2/9/2020 at 10:31 AM, Vesca said:

Mergi la 2 facultati de informatica pe sectii diferite si te asiguri ca ai cursuri de Reverse Engineer. Dupa care, folosesti niste tooluri avansate care trebuiesc platite doar ca sa vezi un cod pe care daca ai fost la liceu de informatica sau te-ai documentat singur pe acasa il scrii in 10 de minute, fara sa treci prin toate cele spuse de catre mine.

Asta da explicatie Vesca :)) 

Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.