Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

[C++] Journey Client v83+

Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
I could be wrong but I think you are going through a phase of development I call "functional procrastination", that is, when there is a higher priority task at hand but you subconsciously delay it because the work load is greater than some other task.

You know you should be doing the more important stuff like mobs, attacking etc. the core functionalities of the game essentially, but instead you delay it and work on something that is simpler in essence and should really only come later in development. The problem with this is that you will be left with all of the exhausting tasks later on and is highly discouraging.

You should focus on having highly maple-like movements, attacking and mobs before you start thinking about npcs and the different menus. You need the core gameplay, working in "chronological" order for lack of a better word.

It's possible that your right, but I didn't even think about this.
The thing is, I don't have a plan in mind what "should" come next after every step. So I actually considered mobs/attacking to be something done after portals worked, just because to get to a mob map I would have to use a portal. I think that that also comes down to preference.
And another thing I have to add is that I didn't really think yet about which features would be difficult to add and which not. This is the first project I have done in c++ (aside from homework) so I don't have a grasp on all the features of the language yet. So for the most part it's hard to tell what's going to be hard and what will be easy, it usually comes down to if I can code something in the same way that I have coded other stuff before or If I need more complicated code.
 
Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
Update:
Github is being added right now. The whole project is still in process of being reorganized, so some methods or classes on github may be unused or unfinished. I still tried my best to make things ordered so that it isn't a complete mess. If people want me to I can try to add comments to some files if the purpose is unclear.

On the state of the project: I reorganized alot of stuff during the last days so some features are temporarily disabled. On the positive side mob spawns work now, and tiled/moving backgrounds now work. As far as changes go there will only be one screen resolution after all, the simple reason being that some backgrounds or maps in v83 are too small for the post-BB resolutions.

Edit: Some more comments on github source: If it hasn't been clear from other posts I've made, the source will not work for just any server. Alot of the packets have been changed so I would not advise anyone to try and compile the source.
The reason for uploading is so that maybe people can point out flaws in the code (and I'm sure there are still alot).

Edit: Added SS of mob spawns:
P1lOr2t - [C++] Journey Client v83+ - RaGEZONE Forums
 

Attachments

You must be registered for see attachments list
Last edited:
Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
Update:

Mobs can now be "killed" (tough no attack animation yet) and item drops show up on the map.
Damage is calculated from equip stats + player stats and sent correctly to the server. I will proably post another video (with better framerate) once I got all the animations and effects done.
 
Joined
Sep 8, 2011
Messages
822
Reaction score
129
Update:

Mobs can now be "killed" (tough no attack animation yet) and item drops show up on the map.
Damage is calculated from equip stats + player stats and sent correctly to the server. I will proably post another video (with better framerate) once I got all the animations and effects done.

I advise strongly against making the damage calculations on client-side due to the possible risk of exploitation.
I'm impressed with how far you got in such a short time, you write your code pretty quick.
 
Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
I advise strongly against making the damage calculations on client-side due to the possible risk of exploitation.
I'm impressed with how far you got in such a short time, you write your code pretty quick.

Don't worry, the server can always check the information the client sends. All of the equips and player stats are mirrored on the server side after all, so a hacked attack info would be noticed immediatly.
 
Divine Celestial
Loyal Member
Joined
Sep 29, 2008
Messages
804
Reaction score
219
I'm blown away by the progress you've made, this is all very promising and can't wait to use this in my projects. I wish you the best. :)
 
Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
Someone has asked me to post a quick guide on how to use the source so here it is:
A warning in advance, it requires a bit of work.

1. Get the source files from the github link.
2. Get the nolifenx source files from the link in the github readme.
3. Make a project out of those (I use visual studio) and compile.
4. Some packets were changed so you will have to change these in your server. I stopped doing this after login, so it's mostly login packets, just check the packets in my packetcreator.cpp and compare.
5. Disable aes encryption and mapleencryption, change the updateIV function in your server to the one the client uses (in crypto.cpp).
6. Use WZ2NX or something similiar to create nx files for ver83. The UI.nx needs to be made from a v159+ wz.
 
Junior Spellweaver
Joined
Aug 13, 2010
Messages
111
Reaction score
16
Someone has asked me to post a quick guide on how to use the source so here it is:
A warning in advance, it requires a bit of work.

1. Get the source files from the github link.
2. Get the nolifenx source files from the link in the github readme.
3. Make a project out of those (I use visual studio) and compile.
4. Some packets were changed so you will have to change these in your server. I stopped doing this after login, so it's mostly login packets, just check the packets in my packetcreator.cpp and compare.
5. Disable aes encryption and mapleencryption, change the updateIV function in your server to the one the client uses (in crypto.cpp).
6. Use WZ2NX or something similiar to create nx files for ver83. The UI.nx needs to be made from a v159+ wz.


I really really love you SYJourney >\\\\\\\\\\\\\\\<
 
Newbie Spellweaver
Joined
Aug 25, 2014
Messages
24
Reaction score
5
Been waiting for something like this since 06!! Keep up the FANTASTIC work! Can't wait to see the next installment.
 
Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
Update:

- You can now attack mobs with regular attacks, damage numbers and mob hp bar have been added
- Exp can be received from the server when killing mobs, so technically you could level up already
- Slopes finally work and backgrounds work a little better, ladders and ropes have been added
- Started working on an inventory (equips)
- Added Face expressions

New video: (killing some mobs and using a portal)


Equip Inventory:
SYJourney - [C++] Journey Client v83+ - RaGEZONE Forums


These are all positive things but there's still alot of glitches and problems occuring. Fixing these usually takes alot more time than actually adding new things, so that's why updates take alot longer now.

Here are some of the most problematic glitches that I haven't figured out yet:
- backgrounds glitch out in some areas, and this can cause the client to slow down
- in rare cases you cannot enter a map, the client will just get "enableactions" from the server
- sometimes the server doesn't send a "monster killed" packet even tough it sends the exp gain, still not sure why this happens
- for some reason I get a lot the same numbers for damage

And these things will still need work before I can move on to adding new stuff:
- Not all mobs can be controlled (moved) from within the client, some are controlled by other clients and are moved through packets
- The same as above for player movement (seeing other players), the player movement packet is sent but I still have to work out how I can handle it so it looks good
- Making mobs able to jump between platforms

Overall the thing I'd like to work on the most is sounds and music, I've played around with them a bit but haven't found a solution that I'm happy with yet.
 
Last edited:
Newbie Spellweaver
Joined
Aug 25, 2014
Messages
24
Reaction score
5
SYJourney!!! #1 fan right here<----- My noobass can't seem to find a reason there isn't a donate button around your name though...
 
BloopBloop
Joined
Aug 9, 2012
Messages
892
Reaction score
275
I decided to take a quick look at the source and found a view issues:
1. you should call delete in the destructor on "cloads"
2.
In this class you create 2 private pointers with new, where as those pointers don't get deleted in the destructur,since both arrays are "const" , i would suggest to make them "const",what allows you to remove the "new". Example::
3. This class is a little tricky, i see here 2 constructors, where one creates 3 pointers and the other creates 1 pointer and takes 2 pointers. Where as those 2 pointers are created withing the session class. All of those pointers don't get deleted.

I also see that you use a lot of times the "new" keyword to create arrays, in the cases you don't return them you don't call delete on them. The cases where you return the pointers they also don't get deleted (char* jrbytes = newchar[4] { 69, 42, 13, 124 };). Creating a new pointer in a function without managing it's memory or asking a other class to mange it is very bad c++ code style, actually it is the WORST thing you could do in c++. If you are required to do this then please use a "shared_prt". Also most of the mistakes in this class can be fixed very easy, just take a look at for example updating the IV's.

The default rule in C++ is: "For every "new" one "delete" is required".

4. . I see you use a mutex "lock" here, now there is nothing wrong with that but it is recommend to either use a "unique_lock" or a "lock_gaurd" for safety. (Choice the one depending on your needs, where is i would say a unique_lock is the one you need)

5. I would also suggest to use references, or even better const references as function parameters where possible expect of pointers (same for returning values). Also a reminder in java is that the "standard types" (int,short,long etc) do all have a fixed size (32 bits,16 bits,64 bits) etc in C++ this is not the case,since you are interacting with Java this "could" give problems. To avoid problems i would suggest to use cstdint.

Here is a example i found in your code what will definitely cause problems.
More info about it:: ( )

Code:
long packet::readLong()
{
   return readbytes<long>(8); 
}

Code:
#include <climits>
#include <cstdint>
#include <iostream>


int main()
{
    std::cout << sizeof(long) << std::endl;
    std::cout << sizeof(long long) << std::endl;
    std::cout << sizeof(int64_t) << std::endl;
    system("pause"); //windows
}

sizeof also works on generic's , what allows you to remove the "size" parameter in readbytes<T>(int size) ,but this might be a little "over" kill for now, also if you specifies a size , please use "size_t size" expect of "int size",size_t does guarant to be big enough to handle the size of the biggest object your system can handle.
 
Last edited:
Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
long post

Thanks for pointing these out, I'll make sure to correct them.

Edit: Looking through the source, theres actually quite alot of places where I forgot to delete pointers. It's kinda weird how I only notice this stuff now that someone mentioned it.
 
Last edited:
BloopBloop
Joined
Aug 9, 2012
Messages
892
Reaction score
275
Thanks for pointing these out, I'll make sure to correct them.

Edit: Looking through the source, there's actually quite alot of places where I forgot to delete pointers. It's kinda weird how I only notice this stuff now that someone mentioned it.

Now don't see me wrong, even tough i said that this is the worst thing you could do in C++, it is in 90% of the time very easy fixable without the need of any design changes, only cases as those
Code:
int* getArray(){ 
    int* ptr = new int[10];
    return ptr;
}

might require a redesign,since in cases as above, the caller of the function has to manage the memory and this makes memory management often very complex (what can results in memory leaks) and should be avoided.The "good" thing is , is that C++ supports shared_ptr's what allows you to do it without a redesign:
Code:
std::shared_ptr<int> getInt()
{
    std::shared_ptr<int> ptr(new int[10]);
    return ptr;
}


Now my own opinion on shared_ptr's is to avoid them in cases as above, (Unless the method is called:"Make new Array" or something, where it is clear that it returns a NEW array), since i still think that this is a bad code style for c++, even tough you aren't required to call delete now.

Only if you are required to create a new instance of some kind of object and the class that creates that instance absolutely can't hold the pointer of the new instance, then use a shared_ptr. A example would be a connectionacceptor,or a factory class ,a connectionacceptor accepts the connection ("new Connection()") and returns it,in this case i would say that a shared_ptr is valid, now it is possible to avoid those type of things, but that is "old-style" C++. Shared_ptr's are there to make your live easier,but don't over use them,don't go for managed languages styles and spam new keyword everywhere, managed languages are designed for that C++ "isn't" as in: try to avoid heap allocations (usage of the new keyword) where possible, , if it can't be avoided ,then try to make sure that the class holds that pointer, so it can be cleaned up in the destructor. If the class can't hold the pointer,then use a shared_ptr.

Example where you can and should avoid the new keyword.
GeneratNumber is the "Managed" style
GenerateNumber2 is the "Unmanaged" style
(This might not be the best example since you could make that array immutable ,but it should give a indication, of how you can avoid the new keyword)
Code:
int GenerateNumber(int num)
{
    int* p = new int[5]{ 10,20,30,40,50 }; //allocated on the heap


    if (num < 5 && num >= 0)
    {
        num = p[num] +12;
    }
    num += p[0];
    num += p[4];
    num -= p[3];
    delete p;
    return num;
}


int GenerateNumber2(int num) 
{
    int numbers[5] = { 10,20,30,40,50 }; //Allocated on the stack
    if (num < 5 && num >= 0)
    {
        num = numbers[num] + 12;
    }
    num += numbers[0];
    num += numbers[4];
    num -= numbers[3];


    return num;


}
 
Last edited:
Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
long post

If you're still talking about the crypto.cpp, the reason why that was so weird is that I originally had all the functions in session.cpp, and then just copypasted the methods over and then later the recvIv/sendIv arrays. So I don't need a return value or parameter at all for that updateiv method, it's just that I somehow forgot about the class while reorganizing things.
I know I should do that stuff immediatly, it's just that I'm not always motivated and feel more like adding something new.
 
BloopBloop
Joined
Aug 9, 2012
Messages
892
Reaction score
275
If you're still talking about the crypto.cpp, the reason why that was so weird is that I originally had all the functions in session.cpp, and then just copypasted the methods over and then later the recvIv/sendIv arrays. So I don't need a return value or parameter at all for that updateiv method, it's just that I somehow forgot about the class while reorganizing things.

I was not talking about the crypto class specificly, but more about the "java" style that should be avoided, i didn't check all the source files,however the crypto class is the best example of it that i found.

A other example would be

"chloads", will it be deleted in a other class or is it a memory leak? (RIP copy paste a of github)
class serverl_h : public vhandler
{
void serverl_h::handle(packet recv)
{
char id = recv.readbyte();
string name = recv.readascii();
char flag = recv.readbyte();
string svrmsg = recv.readascii();
char channels = recv.readbyte();
char* chloads = new char[channels];
for (char i = 0; i < channels; i++)
{
chloads = recv.readbyte();


[TR]
[TD="class: blob-num js-line-number, align: right"][/TD]
[TD="class: blob-code blob-code-inner js-file-line"] }[/TD]
[/TR]
[TR]
[TD="class: blob-num js-line-number, align: right"][/TD]
[TD="class: blob-code blob-code-inner js-file-line"] app.getui()->getfield()->getworlds()->insert(make_pair(id, world(id, name, flag, svrmsg, channels, chloads)));[/TD]
[/TR]
[TR]
[TD="class: blob-num js-line-number, align: right"][/TD]
[TD="class: blob-code blob-code-inner js-file-line"] app.getui()->remove(UI_LOGIN);[/TD]
[/TR]
[TR]
[TD="class: blob-num js-line-number, align: right"][/TD]
[TD="class: blob-code blob-code-inner js-file-line"] app.getui()->add(UI_WORLDSELECT);[/TD]
[/TR]
[TR]
[TD="class: blob-num js-line-number, align: right"][/TD]
[TD="class: blob-code blob-code-inner js-file-line"] app.getui()->enableactions();[/TD]
[/TR]
[TR]
[TD="class: blob-num js-line-number, align: right"][/TD]
[TD="class: blob-code blob-code-inner js-file-line"] }[/TD]
[/TR]
[TR]
[TD="class: blob-num js-line-number, align: right"][/TD]
[TD="class: blob-code blob-code-inner js-file-line"] };[/TD]
[/TR]

 
Last edited:
Elite Diviner
Joined
Mar 24, 2015
Messages
426
Reaction score
416
I was not talking about the crypto class specificly, but more about the "java" style that should be avoided, i didn't check all the source files,however the crypto class is the best example of it that i found.

A other example would be

class serverl_h : public vhandler
{
void serverl_h::handle(packet recv)
{
char id = recv.readbyte();
string name = recv.readascii();
char flag = recv.readbyte();
string svrmsg = recv.readascii();
char channels = recv.readbyte();
char* chloads = new char[channels];
for (char i = 0; i < channels; i++)
{
chloads = recv.readbyte();


[TR]
[TD="class: blob-num js-line-number, align: right"][/TD]
[TD="class: blob-code blob-code-inner js-file-line"] }[/TD]
[/TR]
[TR]
[TD="class: blob-num js-line-number, align: right"][/TD]
[TD="class: blob-code blob-code-inner js-file-line"] app.getui()->getfield()->getworlds()->insert(make_pair(id, world(id, name, flag, svrmsg, channels, chloads)));[/TD]
[/TR]
[TR]
[TD="class: blob-num js-line-number, align: right"][/TD]
[TD="class: blob-code blob-code-inner js-file-line"] app.getui()->remove(UI_LOGIN);[/TD]
[/TR]
[TR]
[TD="class: blob-num js-line-number, align: right"][/TD]
[TD="class: blob-code blob-code-inner js-file-line"] app.getui()->add(UI_WORLDSELECT);[/TD]
[/TR]
[TR]
[TD="class: blob-num js-line-number, align: right"][/TD]
[TD="class: blob-code blob-code-inner js-file-line"] app.getui()->enableactions();[/TD]
[/TR]
[TR]
[TD="class: blob-num js-line-number, align: right"][/TD]
[TD="class: blob-code blob-code-inner js-file-line"] }[/TD]
[/TR]
[TR]
[TD="class: blob-num js-line-number, align: right"][/TD]
[TD="class: blob-code blob-code-inner js-file-line"] };[/TD]
[/TR]



Yes, I was using alot of arrays for this in the beginning (this is from login). You also had this in your first post (it's the same array as chloads), I replaced it with a vector now. (I also read that I should avoid arrays in general is why)
 
Back
Top