Jump to content

Lemongrass

Developer
  • Posts

    547
  • Joined

  • Last visited

  • Days Won

    15

Posts posted by Lemongrass

  1. Lemongrass hat nicht nach dem Client gefragt den du definiert hast sondern nach dem den du nutzt, es könnte ja die Möglichkeit besteht das du ein falsches Client Datum angegeben hast.

    Korrekt.

    @Bilder Wenn du mir sagen würdest wie dann gerne.

    screen000bz.jpg

    screen003u.jpg

    screenelgardro1008.jpg

    screenelgardro1012.jpg

    Versteh jedoch nicht ganz, was die Screenshots jetzt genau sagen sollen. Für mich sieht es so aus, als würde der Login-Server einwandfrei funktionieren und du am Charakter erstellen scheiterst.

    Doch habe ich (Rynbef hat mir sogar ein bisschen weiter geholfen) aber ging dann immernoch net dann habe ich es wieder alleine versucht ,ging wieder net ,dann habe

    ich den selben post von lightning gesehen und habe ihn gefragt,jedoch konnte er auch nicht weiter helfen,wäre sehr net wenn du helfen könntest ,denn habe fast alles versucht.

    Könntest du vielleicht ein wenig genauer sagen, was du gemacht hast?

  2. Ich habe es bei mir getestet und es funktioniert. (Allerdings veränder ich das ja immer bisschen) Kann es leider nicht zeigen, da der NPC noch für mein Server geheim ist...

    Rynbef~

    Sowas ist natürlich in einem Support Topic sehr hilfreich. ;)

    EL Dragon, habe gerade gesehen, dass ich mich anscheinend vertippt habe und statt einem Doppelpunkt einen Strichpunkt gesetzt habe. Versuchs nochmals damit und schau dieses mal bitte auch, ob der Mapserver eine Fehlermeldung schreibt.

    switch(rand(1,4)){ case 1: rentitem 2629,86400; break; case 2: rentitem 2630,86400; break; case 3: rentitem 2410,86400; break; case 4: rentitem 1530,86400; break; }
    

  3. So in order to clean my head and to combine all the information we have gathered so far I have combined the C, C++ and ASM code parts and also the value informations for the variables we have cleared so far.

    Additionally I found something strange in Ai4rei's post:

    struct granny_animation* __cdecl C3dGrannyBoneRes::GetAnimation(int nType, int nAniIdx)
    {
    if( this->m_Animation[nType][nAniIdx] == NULL )
    {
    	g_Unknown1[0] = 0;
    
    	if( nType >= 0 && nType <= 9 )
    	{
    		if( nAniIdx >=0 && nAniIdx <= 4 )
    		{
    			if( nAniIdx )
    			{
    				sprintf(g_Unknown1, "model\\3dmob\\%s", g_session.GetJobName(g_Unknown2[nType]));
    			}
    			else
    			{
    				[color=#ff0000]sprintf(g_Unknown1, "model\\3dmob\\%d_%s.gr2", nType, g_Unknown3[nAniIdx]);[/color]
    			}
    
    			if( g_Unknown1[0] && CFile::IsFileExist(g_Unknown1) )
    			{
    				if( nType != 1 )
    				{
    					this->AddBone(g_Unknown1, nType, nAniIdx);
    				}
    
    				return this->m_Animation[nType][nAniIdx];
    			}
    		}
    	}
    }
    else
    {
    	return this->m_Animation[nType][nAniIdx];
    }
    
    return NULL;
    }

    Shouldn't this line refer to "model\\3dmob_bone\\%d_%s.gr2"?

    After that and seeing the combined output I have come to the same conclusion as you curiosity and that is, that we have to deal with ids higher than 9 by ourselfes. So you might want to take a look at the pseudo code(C/C++ combination) source I came up with and here is the way I guess we should deal with it(I also fixed what I mentioned above):

    #define CUSTOMGRANNYSTARTID 2500
    
    int __thiscall getGrannyModel( void *this, int grannyId, int animationType ){
    // C++ this reference decompiled to C is my guess here
    // It is just like it is setting up the "this" pointer here
    void *objSelfReference;
    // some object self reference - need info about object structure
    // My guess is that it is the set up modelname, which is set in the function
    // readGrannyModelFromDisk after/before reading it
    char *v4;
    char *monster_name;
    
    objSelfReference = this;
    v4 = (char *)this + 4 * ( animationType + 4 * ( 5 * grannyId + 40 ) );
    if( *(_DWORD *)v4 ){
    	return *(_DWORD *)v4;
    }
    
    modelResPath = 0;
    if( (unsigned int)grannyId <= 9 ){
    	if( (unsigned int)animationType <= 4 ){
    		if( animationType ){
    			sprintf( &modelResPath, "model\\3dmob_bone\\%d_%s.gr2", grannyId, animationType[animationType] );
    		}else{
    			monster_name = g_session.GetJobName( grannyModelMappingId2MonsterId[grannyId] );
    			sprintf( &modelResPath, "model\\3dmob\\%s", monster_name );
    		}
    
    		if( modelResPath && fileExists(&modelResPath) ){
    			if( grannyId != 1 ){
    				readGrannyModelFromDisk( objSelfReference, &modelResPath, grannyId, animationType );
    			}
    
    			return *(_DWORD *) v4;
    		}
    	}
    }else{
    	if( (unsigned int)animationType <= 4 ){
    		if( animationType ){
    			sprintf( &modelResPath, "model\\3dmob_bone\\%d_%s.gr2", grannyId, animationType[animationType] );
    		}else{
    			sprintf( &modelResPath, "model\\3dmob\\%d", grannyId );
    		}
    
    		if( modelResPath && fileExists(&modelResPath) ){
    			if( grannyId != 1 ){
    				// I hope this function doesnt make any problems
    				readGrannyModelFromDisk( objSelfReference, &modelResPath, grannyId, animationType );
    			}
    
    			return *(_DWORD *) v4;
    		}
    	}
    }
    
    return NULL;
    }
    
    struct granny_animation* __cdecl C3dGrannyBoneRes::GetAnimation( int grannyId, int animationType ){
    if( this->m_Animation[grannyId][animationType] == NULL ){
    	tmpGrannyModelName[0] = 0;
    
    	if( grannyId >= 0 && grannyId <= 9 ){
    		if( animationType >= 0 && animationType <= 4 ){
    			if( animationType ){
    				sprintf( tmpGrannyModelName, "model\\3dmob\\%s", g_session.GetJobName( grannyModelMappingId2MonsterId[grannyId] ) );
    			}else{
    				sprintf( tmpGrannyModelName, "model\\3dmob_bone\\%d_%s.gr2", grannyId, animationType[animationType] );
    			}
    
    			if( tmpGrannyModelName[0] && CFile::IsFileExist( tmpGrannyModelName ) ){
    				if( grannyId != 1 ){
    					this->AddBone( tmpGrannyModelName, grannyId, animationType );
    				}
    
    				return this->m_Animation[grannyId][animationType];
    			}
    		}
    	}else{
    		if( animationType >= 0 && animationType <= 4 ){
    			if( animationType ){
    				sprintf( tmpGrannyModelName, "model\\3dmob\\%s", g_session.GetJobName( grannyModelMappingId2MonsterId[CUSTOMGRANNYSTARTID + grannyId] ) );
    			}else{
    				sprintf( tmpGrannyModelName, "model\\3dmob_bone\\%d_%s.gr2", grannyId, animationType[animationType] );
    			}
    
    			if( tmpGrannyModelName[0] && CFile::IsFileExist( tmpGrannyModelName ) ){
    				if( grannyId != 1 ){
    					this->AddBone( tmpGrannyModelName, grannyId, animationType );
    				}
    
    				return this->m_Animation[grannyId][animationType];
    			}
    		}
    	}
    }else{
    	return this->m_Animation[grannyId][animationType];
    }
    
    return NULL;
    }
    

    [Edit]:

    Forgot to press the attach button, also the board will not let me upload .c files... :D

    granny.c.txt

    • Upvote 1
  4. Ok thanks for clearing things up a little. I did get something wrong or had some logical issues, whatever...

    So what we actually need to know is how the client comes up with the value for "nType" and where it does that. If we find this, we might be able to change the things to simply load a file with the usual monster id instead of changing it to this curious nType value. But all in all we would need a modification of the function itself and neither me nor you is able to achieve this. I can do assembler, but I do not know how to link the new function pointers correctly, since I have never done/tried something like this up to now. Maybe Ai4rei could help us out with this, if we give him enough information or even the whole function.

  5. Is this possible to add this?

    First release was on 12/14/2011 on kro sakray and 01/04/2012 on kro main server.

    Implemented Battleground Queue System.

    • Players can click on "Battle" button under basic info window and choose desired battleground to queue.
    • Players can use the Queue System from anywhere.
    • Players can enter the battleground, when there are enough players to start a battleground, by clicking on confirmation button.
    • If players leave the Queue System, they will be unable to enter the Queue System again for 1 minute.
    • Players will return to their original position after the end of Battleground if they were in normal field, town or dungeon maps. If players were previously in special dungeon or field maps, they will be returned to the save point.

    1359020393572.png

    I have it partially implemented right now at least the server side management, but I would need a KRO account for packet capturing and a working client with a release date of 01/04/2012 or above. I am sorry that I cannot set up a client myself right now, but I have not followed the whole debate of which client is useable and which is not, and even if I would know that I would not know which diffs would be needed right now. So maybe someone can drop me a PM with a working client after that date with at least the functionality to login or some tool which I can use for that.

  6. Maybe it would be good to insert a note at the bottom of the file /conf/battle/party.conf like:

    // NOTE:

    // Party share range can be set in the file conf/inter_athena.conf

    // Specify the share range by adjusting the value of "party_share_level"

    Would not hurt anyone and would clear things up if someone is looking for it deperately.

    • Upvote 1
  7. Curiosity could you look into the client a little bit deeper and look for the lookup in the mapping table and maybe post it here, because I think that would be the easiest way to recreate the whole GR2 loading function and point it to our own version of a loading function, which would maybe even work out as a WeeDiffPlugin.

    I am sorry that I cannot do this myself, but I only have an ugly decompiled C version of the client not a nice C++ one like you all seem to have.

    • Upvote 1
  8. It means that he copied the table to some free space in the binary and then changed all the addresses to the new one. Additionally he inserted a 10th entry into this mapping table, because he now has more space that he could use. It should work out with other clients too, but the offset has to be calculated for each client date separately and also the free space in the executable has to be looked up by hand for each one.

  9. Also ich hab zwar bis jetzt auf allen Servern von FunRO gespielt, sogar auf der aktuellen missglückten Version, aber von so einem Feature habe ich noch nie gehört. o.O

    Prinzipiell bräuchte man dazu sehr gute Kenntnisse in Sachen Clienthexing, da dies keine Basisfunktionalität des Clients ist. Man müsste also nicht nur den Client um diese Funktionalität erweitern, sondern auch das komplette Management auf der Serverseite dafür programmieren, was meiner Meinung nach ohne einem ordentlichen Sourceedit auch nicht so einfach möglich ist.

    Was es wie bereits erwähnt gibt, sind normale Streamingplugins für Webseiten über die du deinen Usern natürlich Musik ausstrahlen kannst. Das hat jedoch auch nichts mit rAthena zu tun. Was ich nicht ganz verstehe ist deine Aussage bezüglich rAthena, dass nicht alles was auf eAthena möglich war auch hier möglich sei, da rAthena nichts anderes ist, als die zum Zeitpunkt von rAthenas Gründung aktuelleste eAthena Version zwischengespeichert und dann weiterentwickelt um dem Emulator endlich Renewalfunktionalität zu verpassen. Womit genau hast du denn bei rAthena Probleme?

  10. Das Problem liegt hierbei an deiner Logik. Ich weiß nicht ob dir Wahrscheinlichkeitsrechnung was sagt, aber prinzipiell versuchst 4 Mal mit der selben Chance(25%) beim Öffnen des Items ein Rentitem zu erzeugen.

    Ich habe das zwar noch nie probiert, aber versuchs mal hiermit:

    switch(rand(1,4)){ case 1: rentitem 2629,86400; break; case 2: rentitem 2630,86400; break; case 3: rentitem 2410,86400; break; case 4; rentitem 1530,86400; break; }

  11. Could you maybe post the content of the field "animTypeStringTable" as it should show, which animation types are possible so we can line them up more easily.

    Also it seems that you should find the method that calls getGrannyModel since it already sends the a_type which leads to the animation type, which is 0 for the default animation.

    Edit:

    Seems like the animation indexes(?) are static and uses the following IDs:

    void __thiscall C3dGrannyGameActor::SetAction(C3dGrannyGameActor *this, int action, int speed, int type)
    {
     C3dGrannyGameActor *v4; // esi@1
     struct granny_control **v5; // edi@10
     signed int v6; // ebx@10
     int v7; // eax@12
    
     v4 = this;
     this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 0;
     switch ( action )
     {
    case 48:
      this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 4;
      break;
    case 80:
    case 88:
      this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 2;
      break;
    case 64:
      this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 3;
      break;
    case 0:
      this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 0;
      break;
    case 8:
      this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 1;
      break;
    case 24:
      this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 5;
      break;
    case 32:
      this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 11;
      break;
    case 40:
      this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 12;
      break;
    default:
      break;
     }
     this->m_nLastActAnimation = this->baseclass_0.baseclass_0.baseclass_0.m_stateId;
     v5 = this->m_Control;
     v6 = 20;
     do
     {
    C3dGrannyModelRes::DeActAnimation(v4->m_GrannyActorRes, *v5);
    *v5 = 0;
    ++v5;
    --v6;
     }
     while ( v6 );
     v7 = v4->m_nLastActAnimation;
     LODWORD(v4->m_GameClock) = 0;
     if ( type == 1 )
    v4->m_Control[v4->m_nLastActAnimation] = C3dGrannyModelRes::ActAnimation(
    										   v4->m_GrannyActorRes,
    										   v7,
    										   v4->m_Instance,
    										   v4->m_Control[v7],
    										   1);
     else
    v4->m_Control[v4->m_nLastActAnimation] = C3dGrannyModelRes::ActAnimation(
    										   v4->m_GrannyActorRes,
    										   v7,
    										   v4->m_Instance,
    										   v4->m_Control[v7],
    										   0);
    }

    void __thiscall CGrannyPc::SetAction(CGrannyPc *this, int action, int speed, int type)
    {
     if ( this->m_GrannyActorRes )
     {
    this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 0;
    switch ( action )
    {
      case 48:
    	this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 4;
    	CGrannyPc::SetGrannyAction(this, type);
    	break;
      case 80:
      case 88:
    	this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 2;
    	CGrannyPc::SetGrannyAction(this, type);
    	break;
      case 64:
    	this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 3;
    	CGrannyPc::SetGrannyAction(this, type);
    	break;
      case 0:
    	this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 0;
    	CGrannyPc::SetGrannyAction(this, type);
    	break;
      case 8:
    	this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 1;
    	CGrannyPc::SetGrannyAction(this, type);
    	break;
      case 24:
    	this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 5;
    	CGrannyPc::SetGrannyAction(this, type);
    	break;
      case 32:
    	this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 11;
    	CGrannyPc::SetGrannyAction(this, type);
    	break;
      case 40:
    	this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 12;
    	CGrannyPc::SetGrannyAction(this, type);
    	break;
      case 16:
    	this->baseclass_0.baseclass_0.baseclass_0.m_stateId = 6;
    	goto LABEL_12;
      default:
    LABEL_12:
    	CGrannyPc::SetGrannyAction(this, type);
    	break;
    }
     }
    }

    I'll try to discover what are each ActionID, maybe they are indexed like ACTs files are.

    GreenBox could you also please post this function

    CGrannyPc::SetGrannyAction(this, type);

    Thanks in advance. :)

  12. I could basically help you out with this one, if we have a person that can capture packets for me on the official kRO not bRO since the packet structure seems to be different.

    Due to Skotlex commit and the comment in his commit I suggest, that we should start by checking which of the zeros he puts into the packet disables the PIN check and then we can go on by adding further information.

    • Upvote 1
  13. if (strcharinfo(0) == "poring_w02") {

    Ist ein Vergleich ob der Player "poring_w02" heißt, was du meintest ist strcharinfo(3) für den Mapnamen.

    *strcharinfo(<type>)
    
    This function will return either the name, party name or guild name for the
    invoking character. Whatever it returns is determined by type.
    
    0 - Character's name.
    1 - The name of the party they're in if any.
    2 - The name of the guild they're in if any.
    3 - The name of the map the character is in.
    
    If a character is not a member of any party or guild, an empty string will be
    returned when requesting that information.
    

  14. if((gettime(3)>=19 && gettime(3)<9)) goto auf;

    if((gettime(3)>=9 && gettime(3)<19)) goto zu;

    Also das zweite if kann funktionieren, aber das erste ist ein logischer Widerspruch in sich. Die Uhrzeit muss größer als 19 sein und gleichzeitig kleiner als 9.

    Ich glaube nicht, dass so eine Uhrzeit/Zahl existiert.

    Probiers mal einfach mit dem hier:

    dragonia,38,50,1	script	Park Wächter	731,{
    if( gettime(3) >= 9 && gettime(3) < 19 ){
    	mes "^ff0000[Wächter]^000000";
    	mes "Tut mir Leid, tagsüber ist der Park geschlossen.";
    	next;
    	mes "^ff0000[Wächter]^000000";
    	mes "Komm doch um 19:00 Uhr wieder.";
    	close;
    }else{
    	mes "^ff0000[Wächter]^000000";
    	mes "Der Park ist geöffnet.";
    	mes "Willst du hinein?";
    	switch(select("Ja","Nein")){
    		case 1:
    			next;
    			mes "^ff0000[Wächter]^000000";
    			mes "Ich wünsche dir einen schönen Abend...";
    			close2;
    			warp "drag_park.gat", 9, 9;
    			end;
    
    		case 2:
    			next;
    			mes "^ff0000[Wächter]^000000";
    			mes "Okay, dann noch einen schönen Abend...";
    			close;
    	}
    }
    }
    

    Hab dir die OnClock Events entfernt, da du sie ja sowieso nicht verwendet hast.

  15. You are partially right. The in memory implementation would have to be implemented session bound, which means, when the player drops a item it is stored with a UID in his session, if he quits the game, his session would get saved and all UIDs that have not been logged yet would be sent to the database.

    As for the server crash, since a server crash also does not save the session, the inventory will be like he never dropped the item and therefore, no log would be needed.

    And yeah basically it is a combination of the ideas. ;)

×
×
  • Create New...