You are not logged in.

1

Friday, July 8th 2011, 10:36pm

Mathmos Frageecke zu Sourcepawn

Um Threadspam zu vermeiden, dachte ich mir, machst du ein Thema, wo ich alle meine Fragen und Probleme posten kann ;)

So, nun mal zu meiner ersten Frage.

Ich möchte aus einer Cvar den Wert auslesen, dafür gibt’s ja "GetConVar..."
Nun bin ich eben auf der Suche nach dem obigen Befehl auf "FindConVar" gestoßen.
Jetzt würde ich gerne wissen, was es damit auf sich hat. In einigen Plugins verstehe ich das so, dass sie einfach als Abfrage, ob diese Cvar vorhanden ist, genutzt wird.
Wenn ich das richtig verstanden habe, wieso sollte man die Existenz dieser Cvar überprüfen?

fluxX

Super Moderator

Posts: 1,056

Location: Österreich

Occupation: IT Systemadministrator

wcf.user.option.userOption53: Ja

  • Send private message

2

Friday, July 8th 2011, 11:34pm

mit FindConVar bekommst du ein Handle zu einem bereits existierenden convar
zb. mp_freezetime usw

3

Friday, July 8th 2011, 11:55pm

Ok, aber was genau ist eigentlich ein Handle.
Ich sehe das zwar immer und überall, aber so richtig was anfangen kann ich damit noch nicht ;)

Nun aber mal zu einem Problem, an dem ich nun schon einige Zeit dokter aber nichts vernünftiges bei rum komm.
Ich versuche einen Timer zu erstellen und mit diesem dann eine Funktion aus zu rufen, an die dann zwei Variablen übergeben werden sollen...
Mittlerweile habe ich schon einiges probiert, aber leider gab es immer eine Fehlermeldung.

Hier der Timer wie er aktuell aussieht.

Source code

1
CreateTimer(restart_delay, Balance, (teamT, teamCT));


Hier die Funktion wie sie aktuell aussieht.

Source code

1
public Action:Balance(Handle:timer, any:teamT, any:teamCT)

fluxX

Super Moderator

Posts: 1,056

Location: Österreich

Occupation: IT Systemadministrator

wcf.user.option.userOption53: Ja

  • Send private message

4

Saturday, July 9th 2011, 12:38am

in pawn hat jedes handle einen typ. zB cvar handle, timer handle, datenbank handle usw...
Das handle macht ansich nichts, das ist nur ein zeiger auf irgendwas und dann gibt es funktionen denen du dieses handle mitgeben musst, damit die wissen auf was sie ihre funktion machen sollen.
wenn zB das handle geschlossen wird, also der speicher auf den es zeigt überschrieben wird, dann gibt es diese invalid handle errors wie zB bei KillTimer, da das handle halt auf keinen timer mehr zeigt.
und du musst fast alle handles selbst mit CloseHandle() schließen, sonst bleibt der speicher die ganze zeit reserviert und irgendwann ist der halt voll und der server freezed oder so.. wäre nicht so toll ^^
also immer genau auf deine handles aufpassen!

convar handles musst du nicht selbst schließen, das übernimmt sourcemod, wie zb. g_cVarTest = CreateConVar ("sm_test_......);
wenn das plugin unloaded wird, dann werden auch alle offenen handles geschlossen


bei deinem CreateTimer fehlt der Timer.. Zeit ist immer in sekunden.. Zeit kannst halt selber wählen.. vergiss nicht das .0
Versuch mal

Source code

1
CreateTimer(30.0, restart_delay, Balance, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);


poste mir mal die fehler meldung ^^

5

Saturday, July 9th 2011, 7:34am

Egal, ob nach deinem oder nach meinem oder noch anderem Code, kommt der selbe Fehler.



Aber bei mir hat die Zeitangabe nicht gefehlt.
Die Variable "restart_delay" ist meine Zeitangabe ;)

In Beispielen habe ich gesehen, das man TIMER_REAPEAT u.ä. weglassen kann, wenn man nicht vor hat diesen zu wiederholen.
Aber bei deinem Timer werden nicht meine beiden Variablen (teamT, teamCT) an meine Funkion "Balance" übergeben, oder doch?

6

Wednesday, July 13th 2011, 4:25pm

Wiedermal habe ich eine Frage.

Ich möchte in der while Abfrage noch abfragen, ob derjenige schon im Array drin steht.
Dabei darf allerdings nicht das erste Feld abgefragt werden, da ich dort keinen Client drin Speicher.

Source code

1
2
3
4
5
6
7
8
9
for (new i=1; i<g_diff; i++)
{
	do
	{
		client = GetRandomInt(1, MaxClients);
		g_players[i] = client;
	}
	while(!IsClientInGame(client) || GetClientTeam(client) != TS);
}


Gibts es zudem ne Möglichekit ein Array dynamisch zu gestalten?
Was ich möchte, ist ein globales Array, dem ich aber erst jede Runde die größe sage.
Ist dies möglich?

7

Monday, July 18th 2011, 11:58am

Soweit hab ich jetzt alles auf die Reihe bekommen...
Und klappt jetzt auch alles wunderbar, sogar ohne Error Log ^^

Nun möchte ich noch eine Adminabfrage Einbauen.
Hab mich auch schon in einigen andern Plugins umgesehen, aber leider nichts Brauchbares gefunden...

Evt hat ja jemand, speziell fluxX, ein kleines Beispiel ;)

Das was ich bisher probiert habe funzt so rein gar nicht.

Aktueller Stand:
Dabei springen auch 2 Warnings raus

Source code

1
2
3
4
5
6
7
8
9
new AdminId:adminid;
for (new i = 1; i <= MaxClients; i++)
{
  adminid = GetUserAdmin(i);
  if ((IsClientInGame(i) && (GetClientTeam(i) == TS)) && !(GetAdminFlag(adminid, Admin_Kick)))
  {
    PushArrayCell(g_adtClientlist, i);
  }
}

fluxX

Super Moderator

Posts: 1,056

Location: Österreich

Occupation: IT Systemadministrator

wcf.user.option.userOption53: Ja

  • Send private message

8

Monday, July 18th 2011, 3:42pm

Adminabfrage für was?
mehr infos würden schon gut tun.. hab grad kein plan was du willst xD ^^

9

Monday, July 18th 2011, 4:34pm

Naja, es sollen halt nur Leute in das Array geschrieben werden, die kein Admin sind.

Hab jetzt was anderes gefunden, was auch funktioniert, solange die Schleife nur einmal durch läuft.
Sobald sie öfter durch läuft bekomm ich n Fehler.


Source code

1
2
3
4
5
6
7
for (new i = 1; i <= MaxClients; i++)
{
     if (IsClientInGame(i) && IsClientConnected(i) && (GetClientTeam(i) == TS) && (GetUserAdmin(i) == INVALID_ADMIN_ID))
     {
          PushArrayCell(g_adtClientlist, i);
     }
}


Aber hab dich mal in Steam geaddet ;)

Kathy

Intermediate

Posts: 523

Location: München

Occupation: Infrastructure Admin

wcf.user.option.userOption53: Ja

  • Send private message

10

Wednesday, July 20th 2011, 6:26pm

Offtopic: Ich habe deine Frage ecke mal in die "Eigene Scripts" ecke verschoben.
"outage driven infrastructure" ~Nameless friend, ca. 2018

11

Wednesday, July 20th 2011, 9:26pm

Habs nun hinbekommen mit der Adminabfrage.

Nun aber wieder ein neues Problem^^

Ich bekomme immer die schöne Fehlermeldung "tag mismatch"

Hier mal der betroffene Codeschnipsel:

PHP Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
new Handle:g_cvar_checkinterval;
new Handle:g_roundend_counter;

public OnPluginStart()
{
    g_cvar_checkinterval CreateConVar("sm_checkinterval""1.0""team balance after x rounds"0true1.0);

    HookEvent("round_end"Event_RoundEnd)
    g_Cvar_round_restart_delay FindConVar("mp_round_restart_delay");
}

public Event_RoundEnd(Handle:event, const String:name[], bool:dontBroadcast)
{
    new Float:restart_delay GetConVarFloat(g_Cvar_round_restart_delay);    
    g_roundend_counter++;
    if (g_cvar_checkinterval == g_roundend_counter)
    {
        CreateTimer((restart_delay-0.1), Balance);
        g_roundend_counter 0; (<---- tag mismatch Zeile)
    }

This post has been edited 1 times, last edit by "Mathmos" (Jul 20th 2011, 9:42pm)


12

Thursday, July 28th 2011, 8:50am

Kathy hat in einem andern Thread folgende Codezeile verwendet.

PHP Source code

1
if( ( ( inGameOnly ) ? IsClientInGame) : IsClientConnected) ) && !IsFakeClient) )

Nun würde ich mal gerne wissen, was das mit dem Fragezeichen und dem Doppelpunkt auf sich hat.
&& und || ist mir bekannt, aber die andern beiden Operatoren leider nicht.
Habs mittlerweile schon des Öfteren gesehen, aber leider konnte ich mir da keinen Reim drauf bilden.

HSFighter

Administrator

Posts: 1,517

Location: Flensburg

Occupation: Industrieelektroniker

wcf.user.option.userOption53: Nein

  • Send private message

13

Thursday, July 28th 2011, 1:00pm

Kathy hat in einem andern Thread folgende Codezeile verwendet.

PHP Source code

1
if( ( ( inGameOnly ) ? IsClientInGame) : IsClientConnected) ) && !IsFakeClient) )

Nun würde ich mal gerne wissen, was das mit dem Fragezeichen und dem Doppelpunkt auf sich hat.
&& und || ist mir bekannt, aber die andern beiden Operatoren leider nicht.
Habs mittlerweile schon des Öfteren gesehen, aber leider konnte ich mir da keinen Reim drauf bilden.


Das ist die abgekürzte Schreibweise für IF-THEN-ELSE-Konstruktionen.

"?" = "Then" = "{"
":" = "Else" = "} Else {"

PHP Source code

1
(count ($links) > 1) ? ($links join (" | ",$links)) : ($links "");

PHP Source code

1
2
3
4
5
6
if (count ($links) > 1)
{
$links join (" | ",$links);
} else {
$links "";
}



-
Anti Cheat: www.smacbans.com
Kein direkter Support per PM (nur auf Anforderung)

14

Thursday, July 28th 2011, 1:23pm

Ah, alles klar. Danke =)

15

Sunday, December 25th 2011, 6:20pm

Ich bin gerade dabei ein Menu zu erstellen.
Allerdings finde ich es tierisch aufwändig, wenn man mehrere Menüs bzw Sub-Menüs hat.
Das ist jetzt gerade mal ein Menü und ein Sub-Menü und das ist schon recht viel Code.
Geht das nicht irgendwie kürzer?

Spoiler Spoiler

PHP Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <sourcemod>
#include <cstrike>

public OnPluginStart()
{
    RegConsoleCmd("panel_test1"Panel_Test1);
}
 
public PanelHandler1(Handle:menuMenuAction:actionparam1param2)
{
    if (action == MenuAction_Select)
    {
        PrintToConsole(param1"You selected item: %d"param2);
        if (param2 == 1)
        {
            Panel_Test2(param10);
        }
    }
    else if (action == MenuAction_Cancel)
    {
        PrintToServer("Client %d's menu was cancelled.  Reason: %d"param1param2);
    }
}
 
public PanelHandler2(Handle:menuMenuAction:actionparam1param2)
{
    if (action == MenuAction_Select)
    {
        PrintToConsole(param1"You selected item: %d"param2);
        if (param2 == 1)
        {
            Panel_Test1(param10);
        }
    }
    else if (action == MenuAction_Cancel)
    {
        PrintToServer("Client %d's menu was cancelled.  Reason: %d"param1param2);
    }
}

public Action:Panel_Test1(clientargs)
{
    new Handle:panel CreatePanel();
    DrawPanelItem(panel"BLUB1");
    DrawPanelItem(panel"BLUB1");
    DrawPanelItem(panel"BLUB1");
    DrawPanelItem(panel"BLUB1");
    DrawPanelText(panel"BLUB1");
 
    SendPanelToClient(panelclientPanelHandler120);
 
    CloseHandle(panel);
 
    return Plugin_Handled;
}

public Action:Panel_Test2(clientargs)
{
    new Handle:panel CreatePanel();
    DrawPanelItem(panel"BLUB2");
    DrawPanelItem(panel"BLUB2");
    DrawPanelItem(panel"BLUB2");
    DrawPanelItem(panel"BLUB2");
    DrawPanelText(panel"BLUB2");
 
    SendPanelToClient(panelclientPanelHandler220);
 
    CloseHandle(panel);
 
    return Plugin_Handled;
}

LeGone

Beginner

Posts: 46

wcf.user.option.userOption53: Ja

  • Send private message

16

Sunday, December 25th 2011, 11:54pm

AFAIK: Nein =(
Verändere die Sourcewelt so wie du es willst ;)
(Durch modifizieren, spawnen, laden, speichern von Entities)
Extended Grabbermod -> Ent-Control

17

Monday, December 26th 2011, 4:12pm

schade aber auch...

Nun bin ich gerade dabei mich mit SQL zu beschäftigen. Allerdings verstehe ich nur Bahnhof....
Den Code habe ich mir von folgendem Plugin besorgt: http://forums.alliedmods.net/showthread.php?p=582823
Funktioniert auch und erstellt eine Tabelle.
Aber verstehen tu ich nichts. Kennt sich da jemand mit näher aus und kann mir das ein bisschen näher bringen?
Aus dem SM Wiki Eintrag werde ich auch nicht schlauer.

Spoiler Spoiler

PHP Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
new Handle:g_hDatabase INVALID_HANDLE;

public OnPluginStart()
{
    SQL_TConnect(sql_Connect"db_mysql");
}

public sql_Connect(Handle:ownerHandle:hndl, const String:error[], any:data)
{
    if (hndl == INVALID_HANDLE)
    {
        SetFailState("Database failure: %s"error);
    }
    else
    {
        g_hDatabase hndl;
    }

    CreateTables();
    SendQuery("SET NAMES 'utf8'");
}

public sql_Query(Handle:ownerHandle:hndl, const String:error[], any:data)
{
    if (hndl == INVALID_HANDLE)
    {
        ResetPack(data);

        decl String:query[512];
        ReadPackString(dataquerysizeof(query));

        LogError("Query Failed! %s"error);
        LogError("Query: %s"query);
    }
    CloseHandle(data);
}
 
 SendQuery(String:query[])
{
    new Handle:dp CreateDataPack();
    WritePackString(dpquery);
    SQL_TQuery(g_hDatabasesql_Queryquerydp);
}

CreateTables()
{
    static String:sQuery[] = "\
        CREATE TABLE IF NOT EXISTS `db_1`( \
          `id` int(11) NOT NULL AUTO_INCREMENT, \
          `name` varchar(65) NOT NULL, \
          `steamid` varchar(32) NOT NULL, \
          `map` varchar(32) NOT NULL, \
          `serverip` varchar(16) NOT NULL, \
          `serverport` varchar(6) NOT NULL, \
          `game` varchar(32) NOT NULL, \
          `feedback` varchar(255) NOT NULL, \
          `date` timestamp NOT NULL default CURRENT_TIMESTAMP, \
          PRIMARY KEY (`id`) \
        ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;";

    SendQuery(sQuery);
}

18

Monday, December 26th 2011, 10:53pm

So langsam habe ich das wohl doch verstanden, wobei da python echt einfach ist.
Aber wenn mir das doch noch jemand erklären will habe ich nichts dagegen =)

Nun habe ich vor, da das Menü und der SQL Kram doch einige Zeilen in Anspruch nehmen, das ganze auszulagern.
Soll heißen, ich schreibe das Menü und den SQL Kram in eine extra Datei und include sie dann in meine main.sp.

Nun aber zu meine Problem.
ZB. brauche ich die Funktion "public OnPluginStart()" in meiner main.sp aber auch in der sql.inc (ich habe es einfach mal so genannt, ist ja glaube ich egal ob sp oder inc oder blub, oder?).
Wenn ich das nun compiliere bekomme ich eine Fehlermeldung, dass OnPluginStart schon definiert ist.
Wie kann ich das nun umgehen? Bzw, wie muss man es schreiben, damit ich Funktionen in mehrern Dateien benutzen kann?

Edit: Mir ist gerade die Idee gekommen, dass ich die Funktion OnPluginStart in der sql.in umbenennen kann, zB in SQL_OnPluginStart und dies dann von der originalen OnPluginStart Funktion, die sich ja in der main.sp befindet, aufrufen lasse. Ist zwar nicht die optimalste Lösugn, aber würde ja funktionieren.
btw, wann muss ich eignetlich vor ne Funktion "public" schreiben und wann nicht?

This post has been edited 1 times, last edit by "Mathmos" (Dec 26th 2011, 11:02pm)


Impact

Super Moderator

Posts: 1,276

wcf.user.option.userOption53: Nein

  • Send private message

19

Monday, December 26th 2011, 11:36pm

Viele Fragen auf einmal :)
  • public: A callback function that is visible to the application and other scripts.

Sprich Callbacks, Events, Vordefinierte Forwards, diese brauchen ein Public.
Steht aber auch alles in der Introduction...

Ich musste diese Technik bisher noch nicht anwenden, aber wenn du danach arbeitest hast du normalerweise immer eine main.sp, diese ist meist sehr klein da darin kein wirklicher Code steht.
In dieser deklarierst du alles was du brauchst, Hooks, Callbacks, Events, etc.
In der jeweiligen Datei hast du dann du dann deinen Callback der durch die main.sp erstellt wurde.
Im Prinzip kommt dabei das gleiche Raus, allerdings kannst du das machen wie es dir lieb ist, performancemäßig sollte es keine besonders großen Auswirkungen haben, ansonsten kannst du ja mit dem Profiler selbst testen.

Ich hab dir im Anhang ein kleines Beispiel geschrieben.

MfG
Impact
Impact has attached the following files:
  • main.sp (398 Byte - 151 times downloaded - latest: Today, 1:37am)
  • events.sp (214 Byte - 141 times downloaded - latest: Today, 1:46am)
  • commands.sp (198 Byte - 151 times downloaded - latest: Jul 19th 2025, 3:32pm)

This post has been edited 1 times, last edit by "Impact" (Dec 26th 2011, 11:49pm)


20

Tuesday, December 27th 2011, 12:17am

Jap, es muss sich ja auch lohnen ;)

Erstmal danke, aber kannst du das auch noch so formulieren, dass ein "nicht programmierer" es versteht?
Ich verstehe die ganzen Begriffe wie, Callbacks, Forwards,....., nicht.
Aber der Link hilft mir bestimmt bei dem ein oder andern Dingen weiter.

Bei deinem Beispiel hast du ein paar Sachen drin, wo ich auch gleich mal nachfragen muss =)

#pragma semicolon 1 : Das habe ich schon bei einigen Addons gesehen, aber wofür das ganze gut ist konnte mir google auch nicht so richtig sagen.

Action: : Wieso steht das in den Funktionen und was bewirkt es?

Source code

1
2
3
4
#if defined _myevents_included
  #endinput
#endif
#define _myevents_included

Für was ist das gut?