[ANET] A6 Pointer in entity.skill speichern

Posted By: JoGa

[ANET] A6 Pointer in entity.skill speichern - 07/15/10 08:23

Hallo
Im Singleplayer bin ich oft so vorgegangen, dass ich von Entities den pointer in einem Skill abgespeichert habe, wenn ich den Pointer noch brauchte (handle(pointer)+ptr_for_handle(skill);).
Nun funktioniert im Multiplayer bei mir der pointer player nicht als lokaler Pointer:
Beispiel:
Spieler 1 ist player, klinkt sich ein und bekommt eine Entity an sich angehängt - alles funktioniert
Spieler 2 joint, bekommt auch eine neue Entity an sich angehängt, aber es hängen beide Entitys an ihm, der erste Spieler hat keins mehr an sich.
Daher denk ich, dass player nicht lokal sondern global ist.

Nun hab ich versucht, dem Problem aus dem Weg zu gehn, indem ich wie oben angesprochen mit handle und ptr_for_handle arbeite, um die jeweiligen Spieler-Pointer-IDs bei den angehängten Entities abzuspeichern und dann wieder aufzurufen, damit sie sich an die you = ptr_for_handle(my.skillx) dranhängen.
Da bekomme ich aber folgende Fehlermeldung:
"Empty pointer in enet_ent_globpointer: vec_sub(temp.x,you.x)" (bei einer mit enet_ent_create erstellten Entity)
D.h. ich kann die handle - und ptr_for_hanlde-befehle mit ANET nicht verwenden? Wurde ja auch im Manual gewarnt, dass man befehle nicht vermischen darf. - Weis jemand die Lösung meines Problems, warum ich meine Pointer nicht richtig verwenden kann?
2 globale Entities, die die Spieler sind, brauchen einfach noch jeder ein globales Entitie als "Anhängsel" (zB. bei Panzersimulationen der Turm, bei Hack&Slay die Waffen usw...)
Aber irgendwie steh ich sowohl mit den Pointern grad auf dem Kriegsfuß als auch momentan grad auf dem Schlauch, glaub ich ^^ -.-
Posted By: Dark_samurai

Re: [ANET] A6 Pointer in entity.skill speichern - 07/15/10 09:35

Gilt nur für globale Entities (erstellt mit enet_ent_create()):
Wenn du einen Pointer brauchst, der auf allen PCs gleich ist musst du ihn per enet_get_globpointer(entityxyz); ermitteln. Auf jedem einzelnen PC kannst du dann diesen globalen Pointer per enet_get_locpointer(globalerpointervonvorher); umwandeln und so die Entity wie im Singleplayer ansprechen.
Zur Erklärung: Der Server führt eine Liste 0-unendlich in der nach der Reihe die globalen Entities eingetragen sind. Der globale Pointer ist nichts anderes als die Nummer des Eintrags. Jeder Client hat ein Duplikat der Liste in dem der lokale Pointer (also der Pointer am jeweiligen Client) gespeichert ist. Mit enet_get_locpointer() wird einfach dieser Pointer aus der Liste ausgelesen.

handle und ptr_for_handle() benötigst du gar nicht. Dafür sind die obigen Funktionen vorgesehen.
Posted By: JoGa

Re: [ANET] A6 Pointer in entity.skill speichern - 07/15/10 12:29

wow, super, genau das hab ich gesucht, danke!

Jetzt hab ich "nur noch" ein Problem gerade bemerkt, als ich die Entityanzahl überprüft habe:
Sobald sich ein neuer Client einloggt, werden die anderen Spieler-figuren alle im Grund doppelt erstellt und werden dann vom ersten Spieler(serverclient) gesteuert - hast du da ne spontane Idee, was das sein könnte? Irgendein bekannter ANET-Anfänger-Fehler?
Posted By: Razoron

Re: [ANET] A6 Pointer in entity.skill speichern - 07/15/10 13:07

Also dafür bräuchte man etwas code. laugh
Wer erstellt den die Entity? der Serverclient oder der Client selber?
Und nur mal so, hast du dir schon das "Simple 3D Chat" Tutorial durchgelesen?
Sehr hilfreich!
Posted By: JoGa

Re: [ANET] A6 Pointer in entity.skill speichern - 07/15/10 13:32

Jop, hab ich durchgelesen, ich hab daraus sogar Code für den Anfang kopiert -.- *schähm* ^^
über die while-Schleifen oder das mit dem Pan-Winkel bei der Bewegung bitte darüber weg sehn, ich schreib das meist etwas kompliziert hin und wenn es vom Prinzip funktioniert, optimiere ich das dann noch ^^
Okay, dann hier etwas Code:
Die mainfunktion steht im ersten Code-Block zu unterst. Syntaxfehler(sowas wie Semikolon vergessen oder so), die eigentlich Fehlermeldungen produzieren würden, sind mir dann beim hier hereinkopieren passiert, die Engine läuft das bei mir problemlos durch.
Code:
function create_player()
{
	enet_ent_create("spieler01_unten.mdl",vector(random(100), 0, 0),"move_player");
	wait(1);
}

string playername_str = "#50"; 
//client event beim einklinken
function connected_with_server(sender, msg)
{
	inkey(playername_str); //Lässt den Spieler einen Spielernamen eingeben 
	enet_set_playername(playername_str); //Speichert den Spielernamen 
	if(enet_get_connection() == CLIENT_MODE) //if started as client
	{
		error("neuer client");
		//level_load(msg); //loads the level which is loaded on the server
		level_load("level_001__test.wmb"); //loads the level which is loaded on the server
		wait(3); //wait until the level is loaded
		enet_ent_synchronize(); //sends a synchronizing request
	}
	else //started as server or server/client
	{
		error("neuer server");
		create_player(); //creates the correct character
	}
}

function synchronizing_complete(sender, msg)
{
	create_player(); //creates the correct character
}

function start_client(ip)
{l
	enet_init_client(ip,used_port,""); //initializes a client
}

function start_server()
{
	while(key_F1){wait(1);} // zum schnell testen mit F1 server
	level_load("level_001__test.wmb"); //Loads the first Level
	wait(3); //wait until the level is loaded
	while((enet_init_server(used_port,max_players,""))==ANET_ERROR)	{wait(1);}
	enet_set_level("level_001__test.wmb"); //sets the level
	wait(4);
	//start_client("localhost"); // server spielt auch mit
	start_client("255.255.255.255");
}

function test_start_client() //zum testen den Client dazu
{
	while(1)
	{
		if(KEY_F2)
		{
			//start_client("localhost");
			start_client("255.255.255.255");
			break;
		}
		wait(1);
	}
}

function main()
{
	fps_max = 60;
	wait(1); //wait for the plugin to get loaded
	if((enet_init())==ANET_ERROR){exit;}
	anet_set_compatibility(1);
//enet_svset_event(EVENT_DISCONNECTED,"client_disconnected");
	enet_clset_event(EVENT_CONNECTED,"connected_with_server");
	//enet_clset_event(EVENT_DISCONNECTED,"disconnected_from_server");
	enet_clset_event(EVENT_SYNCHRONIZED,"synchronizing_complete");
	//enet_clset_event(EVENT_LEVEL,"change_level_event");
	//sets userevents:
	//enet_svset_event(16,"kick_client");
	//enet_svset_event(17,"receive_chatmsg");
	//enet_clset_event(17,"receive_chatmsg");
	level_load(""); //loads an empty level
	wait(3); //wait until the level is loaded
	//shows the mouse
	mouse_mode = 1;
	mouse_map = arrow_bmap;
	test_start_client(); //temp
	while(1)
	{
		//gets some info vars:
		enet_connection = enet_get_connection();
		enet_clientid = enet_get_clientid();
		enet_clients = enet_connected_clients();
		ping = enet_get_ping();
		//controls the mouse:
		MOUSE_POS.X = POINTER.X;
		MOUSE_POS.Y = POINTER.Y;
		wait(1);
	}
}
ON_F1 = start_server(); //test


das ist die Mainfunktion und was den Server+Client initialisiert.
Die Spielerfunktion ist hier:
Code:
function oberes_teil()
{
	while(enet_ent_globpointer(my) == ANET_ERROR) {wait(1);}
	my.passable = on;
	while(1)
	{
		you = enet_ent_locpointer(my.entity_handle);
		vec_set(my.x,you.x);
		vec_set(temp.x,vector(mouse_pos.x,mouse_pos.y,camera_dist));
		vec_for_screen(temp,camera);
		temp.z = 0;
		vec_sub (temp.x, you.x);
		vec_to_angle (my.pan, temp); // rotate it towards the target
		wait(1);
	}
}
function move_player() 
{
	my.leben = 100;
	my.max_leben = 100;
	my.mana = 100;
	my.max_mana = 100;
	var dist_move[3];
	var moved_dist; //die Distanz, die zurückgelegt wurde (damit wird überprüft, ob Spieler bewegt wurde, wenn ja -> broadcast)
	var moved_pan; //die Drehung, die zurückgelegt wurde (damit wird überprüft, ob Spieler bewegt wurde, wenn ja -> broadcast)
	while(enet_ent_globpointer(my) == ANET_ERROR) {wait(1);}
	you = enet_ent_create("spieler01_oben.mdl",vector(my.x,my.y,my.z),"oberes_teil");
	while(enet_ent_globpointer(you) == ANET_ERROR) {wait(1);}
	you.entity_handle = enet_ent_globpointer(my);
//	updates();	//updates für Charakter-Wert-Balken u.ä.
	while(1)
	{
		if(enet_ent_creator(enet_ent_globpointer(my)) == enet_get_clientid()) 
		{
			while(my.leben>0) 
			{
				if(key_A+key_W+key_D+key_S>0)	{dist_move.x = 25*time;} else {dist_move.x = 0;}


				moved_dist = c_move(my,dist_move,nullvector,IGNORE_PASSABLE|GLIDE|IGNORE_PUSH); 
				if(abs(moved_dist) > 0) //Wenn sich die Entity bewegt hat 
				{ 
					enet_set_unreliable(1); //damit die Position unreliable gesendet wird 
					//sendet die neue Position an alle: 
					enet_send_pos(enet_ent_globpointer(my),BROADCAST,0); 
					enet_set_unreliable(0); //schaltet unreliable wieder aus 
					//damit andere Sendfunktionen nicht beeinflusst werden 
				}
				if(key_W)	{moved_pan =  90;}
				if(key_A)	{moved_pan = 180;}
				if(key_S)	{moved_pan = 270;}
				if(key_D)	{moved_pan =   0;}
				if(key_W && key_D)	{moved_pan =  45;}
				if(key_S && key_D)	{moved_pan = 315;}
				if(key_S && key_A)	{moved_pan = 225;}
				if(key_W && key_A)	{moved_pan = 135;}
				if(moved_pan != my.pan) //wenn der Player gedreht wurde 
				{
					my.pan = moved_pan;
					enet_set_unreliable(1); 
					//sendet die neuen Winkel an alle: 
					enet_send_angle(enet_ent_globpointer(my),BROADCAST,ONLYSEND_PAN);
					enet_set_unreliable(0); 
				}
				kamera_bewegung();  //if(key_F){erster_slot+=1;} enet_send_skill(enet_ent_globpointer(my),1,1,BROADCAST);
				wait(1);
			}
		}
		wait(1);
	}
}


Ich hab das aus dem 3D-Chat-workshop(der echt toll ist!).
Der Server wird erstellt.
Er clinkt sich dabei selbst als Client ein und erstellt ne Spielfigur.
Clients joinen und per enet_clset_event->EVENT_CONNECTED wird synchronisiert.
Durch das ausgelöste enet_clset_event->EVENT_SYNCHRONIZED wird eine Spielfigur für den Clienten erstellt.
Doch wenn ich das ausführe, passiert das, was ich vorhin beschrieben habe -
1. Servervlient: 2 entities (ober- und unterkörper)
weiterer client: 6 entities
dritter client: 12 entities
jeder kann sich bewegen, es ist alles "normal" - mir ist das erst garnicht aufgefallen, nur durch die Anzahl der Entities später.
Die, die zusätzlich "nicht da sein dürften" "kleben" an der Serverclient-Entity.
Posted By: Dark_samurai

Re: [ANET] A6 Pointer in entity.skill speichern - 07/15/10 16:32

Das Problem liegt in deiner Playerfunktion. Diese wird von JEDEM Rechner ausgeführt => es wird von jedem enet_ent_create("spieler01_oben.mdl"...); ausgeführt. enet_ent_create() erzeugt automatisch auf jedem Rechner eine Entity. Deswegen die vielen Entities.

Ich würde enet_ent_create("spieler01_oben.mdl"...); in dem Teil der Funktion ausführen, der nur vom Ersteller der Spielerentity ausgeführt wird. Also nach if(enet_ent_creator(enet_ent_globpointer(my)) == enet_get_clientid()). Dann wird die Funktion nur einmal ausgeführt und es wird dadurch auch nur eine Entity auf jedem Rechner erstellt.
Posted By: JoGa

Re: [ANET] A6 Pointer in entity.skill speichern [SOLVED] - 07/15/10 17:35

Wow, Leute, danke, wenn wir im Pub säßen, würd ich euch zwei ne Runde spendieren wink
Das Problem war, wie Dark_samurai erkannt hat, dass das Entity von jedem Client erstellt wurde, anstatt nur von dem zugehörigen Client.
Danach tauchte noch ein weiteres Problem meines Codes auf und zwar, dass das obere angefügte Teil trotzdem nicht an seiner Position, sondern an der Position vom serverclient-Entity war.
Das habe ich dann mit dem roten Einschub, weiter unten zu sehen, behoben. Zwar wird das jetzt jeden Tick gesendet, aber es klappt wenigstens mal und jetzt kann ich ja das senden noch einschränken, das ist ja dann machbar für mich.
Code:
function oberes_teil()
{
	while(enet_ent_globpointer(my) == ANET_ERROR) {wait(1);}
	//my.entity_handle = handle(you);
	//player_attacs();
	my.passable = on;
	my.transparent = on;
	while(1)
	{
		you = enet_ent_locpointer(my.entity_handle);
		vec_set(my.x,you.x);
		vec_set(temp.x,vector(mouse_pos.x,mouse_pos.y,camera_dist));
		vec_for_screen(temp,camera);
		temp.z = 0;
		//you = 
		vec_sub (temp.x, you.x);
		vec_to_angle (my.pan, temp); // rotate it towards the target
		/*EINSCHUB*/if(enet_ent_creator(enet_ent_globpointer(my)) == enet_get_clientid())/*EINSCHUB*/
		{
			enet_send_pos(enet_ent_globpointer(my),BROADCAST,0);
			enet_send_angle(enet_ent_globpointer(my),BROADCAST,ONLYSEND_PAN);
		}
		wait(1);
	}
}


Ich denk, dass das rote, zweite Problem, das nach dem, das dark_samurai gelöst hat, auftrat; mit dem ersten zusammenhing.
Jeder Spieler hat die ganzen angehängten Entitiy-Funktionen der anderen auch ausgeführt und dann "sich" alle angehängt, der Server läuft da dann wohl als letztes durch und hat dann die angehängten Entities an sich - aber das ist nur ein Erklärungsversuch von mir, genau hab ichs noch nicht geblickt, zum Glück xD (oh gott, mit so ner Einstellung werd ich nie Programmierer xD) funktionierts ^^ und ich gies erstmal ne Runde Garten und dann noch mal schaun.

DANKE!!
allein dem Support ist es Wert, sich ANET zuzulegen ;-)
(was ich dann hoffentlich auch mach, wenn das jetzt einigermaßen läuft und ich mein erstes kleines Multiplayerspiel dann fertig bekomm)

EDIT: rot markierne hat nicht geklappt, habs Einschub genannt. (kommentar vor und nach der Codezeile)
Posted By: Dark_samurai

Re: [ANET] A6 Pointer in entity.skill speichern [SOLVED] - 07/16/10 09:59

Dadurch, dass ja bereits die Position des Spielers aktualisiert wird ist es nicht nodwendig auch die Position von "oberes_teil" zu senden, da dies ja die selbe Position hat wie der Player. Aber das hast du ja schon richtig erkannt.

Das Problem ist glaube ich, dass du my.entity_handle nur lokal speicherst (also auf dem PC der den Player und "oberes_teil" erstellt hat). Sende per enet_send_skills() den Skill zuerst an alle. Dann hat die Entity "oberes_teil" auf allen Rechnern im Skill my.entity_handle den globalen Pointer der zugehörigen Playerentity gespeichert. Dann sollte eigentlich alles funktionieren auch ohne dem Einschub.

Wenn du den Skill nicht sendest ist er auf den anderen PCs immer 0. D.h. die Entity wird an die Entity angehängt die den globalen Pointer 0 hat also die, die als erstes erstellt wurde wink
Posted By: JoGa

Re: [ANET] A6 nochmal kleines Problem mit glob_pointer - 07/17/10 20:54

Okay, super - funktioniert einwandfrei.
Jetzt hab ich noch eine Frage, dann hab ich warscheinlich das Multiplayerplugin einigermaßen als Anwender kapiert ^^

Folgendes Problem:
Entity wird in WED gesetzt. (als "Medipack" - spieler läuft drüber und bekommt Hp gutgeschrieben)

Wenn ich es in WED setze, wird es dank synchronize-Befehl am Anfang ja ein globales Entity.
Trotzdem bekomme ich eine Empty-Pointermeldung, wenn ich das Entity mit
enet_ent_remove(enet_ent_globpointer(my));
entfernen möchte.
Per ent_remove geht, aber dann ists ja nur auf dem jeweiligen Clienten gelöscht und nicht global.


Code:
function item_hp_event()
{
	my.passable = on;
	if(you.gesinnung != spieler)	{my.leben = 0; return;}
	you.leben += my.leben;
	my.leben = 0;
}

action item_hp
{
	while(enet_get_connection() == NO_CONNECTION) 	{wait(1);} //wartet bis ein Service initialisiert wird 
	if(enet_get_connection() == SERVER_MODE || enet_get_connection() == CLIENT_SERVER_MODE)  {enet_ent_register(my);} // Server registriert 
	while(enet_ent_globpointer(my) == ANET_ERROR) 	{wait(1);} //wartet bis der Entity ein globaler Pointer zugewiesen wird 
	my.push = -1;
	my.leben = 25;
	my.event = item_hp_event;
	my.enable_push = on;
	while(my.leben>0)
	{
		wait(1);
	}
	/*if(enet_get_connection() == CLIENT_SERVER_MODE) {*/enet_ent_remove(enet_ent_globpointer(my));//}
}


Meinem Code anzusehn habe ich schon etwas probiert:
- anfangs das Entity nochmal als globales Entity registrieren
- und am Ende die Entity nur vom Clientserver zu löschen, damit das nicht x-mal ausgeführt wird.

Irgendwie wieder ein Denkfehler meinerseits - ich hoff, ich muss euch diesbezüglich nicht mit noch mehr dupfbackenfragen plagen >.<
Posted By: Dark_samurai

Re: [ANET] A6 nochmal kleines Problem mit glob_pointer - 07/18/10 17:11

Quote:
Wenn ich es in WED setze, wird es dank synchronize-Befehl am Anfang ja ein globales Entity.


Nein, dafür gibt es diese Funktion: enet_ent_register().
Einfach am Server alle solche Entities mit dieser Funktion in eine globale umwandeln. Danach wird beim Synchronisieren auch bei den Clients jede Entity zu globalen.
Posted By: JoGa

Re: [ANET] A6 nochmal kleines Problem mit glob_pointer - 07/18/10 23:50

Okay, es funktioniert.
Mein Code hat erst nicht funktioniert, mir wurde angezeigt, dass der globale Pointer = ANET_ERROR war.
Hab aus dem Beispiel aus dem Manual irgendwie falsch interpretiert, dass enet_ent_register nur auf dem Server ausgeführt werden muss.
Auf jeden Fall klappts jetzt, wenn jeder enet_ent_register(my); aufruft.
Danke!

btw: im manual steht bei der Funktion enet_send_skills in den Beispielen die funktion nur mit enet_send_skill - ohne Plural-"s".
Warscheinlich Tippfehler, führt, wenn man das nicht aus der Kopfzeile, sondern aus den Beispielen liest im eigenen Code zu Kopfzerbrechen xD
Posted By: Dark_samurai

Re: [ANET] A6 nochmal kleines Problem mit glob_pointer - 07/19/10 08:30

Sobald enet_ent_register() am Server ausgeführt wurde, wird durch das Synchronisieren automatisch auf den Clients die Entity auch in eine globale umgewandelt. Überprüfe das noch mal, wenn du auf den Clients enet_ent_register() nochmal ausführst, bekommt diese ev. einen anderen globalen Pointer als am Server.
Wenn nicht synchronisiert wird, dann musst du enet_ent_register() auf jedem Rechner ausführen.

Den Tippfehler habe ich behoben, danke.
© 2024 lite-C Forums