-
Posts
194 -
Joined
-
Last visited
-
Days Won
23 -
Feedback
0%
Content Type
Forums
Store
Third Party - Providers Directory
Feature Plan
Release Notes
Docs
Events
Posts posted by Distraught
-
-
Compile your game with -g flag for debug symbols and if it's not a live environment I suggest you use -O0 also.
-
Change
std::vector <LPITEM> item_gets(NULL);
to
std::vector <LPITEM> item_gets;
And by the way those item_gets->GetName() at the end should be item_gets[i]->GetName()
-
No one defined what they mean by interacting real-time. Interacting real time can also mean like sending messages what could be achieved. What I was talking about still makes sense as I told them their possibilities, just really have your time understanding it. This construction could matter tho. You ought to understand what I am saying instead of just trying to get it personal because your message was nothing but trying to be bitchy about anything.
-
Hey guys,
I just programmed this feature for my server but I thought it can be really useful for everyone so now I release it.
This stuff is about how you can load images, etc. in the game without directly packing it into the client but uploading them to a web-server. In this tutorial we will make it work for images, but you can extend it to any type of file you want.
There are not much requirements we only use up to C++11 features and you have to have libcurl library.
Open up EterLib/ResourceManager.h and add add the following to the end of the class (don't forget to include <future> and <utility>):
private: std::list<std::future<CResource*>> ongoingDownloads; public: void AddDownload(std::future<CResource*>&& f) { ongoingDownloads.emplace_back(std::forward<std::future<CResource*>>(f)); }
Go to EterLib/ResourceManager.cpp and find the CResourceManager::Update function, add the following to the end of it:
for (auto it = ongoingDownloads.begin(); it != ongoingDownloads.end();) { if (it->wait_for(std::chrono::seconds(0)) == std::future_status::ready) { it->get()->LoadDownloadedData(); it = ongoingDownloads.erase(it); } else { ++it; } }
Next, open EterLib/Resource.h, find the constructor and modify it like:
CResource(const char* c_szFileName, bool _loadFromNetwork = false);
After add the following to the end of the class:
protected: bool loadFromNetwork; private: std::vector<BYTE> downloadedData; public: void LoadDownloadedData();
Then go to EterLib/Resource.cpp, find the constructor and also modify it like:
CResource::CResource(const char* c_szFileName, bool _loadFromNetwork) : me_state(STATE_EMPTY) , loadFromNetwork(_loadFromNetwork) { SetFileName(c_szFileName); }
In the same file, add this to the beginning right after the includes:
#include <curl/curl.h> #include "ResourceManager.h" #define ASSET_SERVER "http://assets.my-website.com/" static size_t CurlWriteCallback(void* contents, size_t size, size_t nmemb, void* userp) { if (nullptr != userp) { std::vector<BYTE>& vec = *((std::vector<BYTE>*)userp); vec.reserve(vec.size() + (size * nmemb)); for (size_t i = 0; i < size * nmemb; ++i) { vec.push_back(((BYTE*)contents)[i]); } } return size * nmemb; } void CResource::LoadDownloadedData() { if (downloadedData.empty()) return; Clear(); if (OnLoad(downloadedData.size(), downloadedData.data())) { me_state = STATE_EXIST; } else { Tracef("CResource::Load Error %s\n", GetFileName()); me_state = STATE_ERROR; } downloadedData.clear(); }
Now, - still in the same file - find CResource::Load function and modify it like this:
void CResource::Load() { if (me_state != STATE_EMPTY) return; std::string fileName = GetFileName(); if (loadFromNetwork && downloadedData.empty()) { CResourceManager::instance().AddDownload(std::move(std::async(std::launch::async | std::launch::deferred, [this, fileName]() { std::string url = ASSET_SERVER; url += fileName; CURL* curl = curl_easy_init(); if (curl) { curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &downloadedData); curl_easy_perform(curl); curl_easy_cleanup(curl); } return this; }))); fileName = "d:/ymir work/ui/placeholder.tga"; } DWORD dwStart = ELTimer_GetMSec(); CMappedFile file; LPCVOID fileData; //Tracenf("Load %s", c_szFileName); if (CEterPackManager::Instance().Get(file, fileName.c_str(), &fileData)) { m_dwLoadCostMiliiSecond = ELTimer_GetMSec() - dwStart; //Tracef("CResource::Load %s (%d bytes) in %d ms\n", c_szFileName, file.Size(), m_dwLoadCostMiliiSecond); if (OnLoad(file.Size(), fileData)) { me_state = STATE_EXIST; } else { Tracef("CResource::Load Error %s\n", fileName.c_str()); me_state = STATE_ERROR; return; } } else { if (OnLoad(0, NULL)) me_state = STATE_EXIST; else { Tracef("CResource::Load file not exist %s\n", fileName.c_str()); me_state = STATE_ERROR; } } }
Still in Resource.cpp, find the CResource::Reload function and modify like:
void CResource::Reload() { Tracef("CResource::Reload %s\n", GetFileName()); if (loadFromNetwork) { if (downloadedData.empty()) { std::string fileName = GetFileName(); CResourceManager::instance().AddDownload(std::move(std::async(std::launch::async | std::launch::deferred, [this, fileName]() { std::string url = ASSET_SERVER; url += "/"; url += fileName; CURL* curl = curl_easy_init(); if (curl) { curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &downloadedData); curl_easy_perform(curl); curl_easy_cleanup(curl); } return this; }))); } } else { Clear(); CMappedFile file; LPCVOID fileData; if (CEterPackManager::Instance().Get(file, GetFileName(), &fileData)) { if (OnLoad(file.Size(), fileData)) { me_state = STATE_EXIST; } else { me_state = STATE_ERROR; return; } } else { if (OnLoad(0, NULL)) me_state = STATE_EXIST; else { me_state = STATE_ERROR; } } } }
Open EterLib/GrpImage.h and modify the constructor:
CGraphicImage(const char* c_szFileName, DWORD dwFilter = D3DX_FILTER_LINEAR, bool loadFromNetwork = false);
In EterLib/GrpImage.cpp also modify it:
CGraphicImage::CGraphicImage(const char * c_szFileName, DWORD dwFilter, bool loadFromNetwork) : CResource(c_szFileName, loadFromNetwork) , m_dwFilter(dwFilter) { m_rect.bottom = m_rect.right = m_rect.top = m_rect.left = 0; }
Finally open ScriptLib/Resource.cpp and add this somewhere the beginning:
CResource* NewOnlineImage(const char* c_szFileName) { return new CGraphicImage(c_szFileName, D3DX_FILTER_LINEAR, true); }
Go down where you see m_resManager.RegisterResourceNewFunctionPointer("jpg", NewImage); and add after:
m_resManager.RegisterResourceNewFunctionPointer("oimg", NewOnlineImage);
We're done! Now if you use *.oimg extension anywhere it will load them from what you define as ASSET_SERVER in EterLib/Resource.cpp (http://assets.my-website.com/filename.oimg). You have to rename the image you upload from the original extension to oimg!
Put a placeholder image at "d:\ymir work\ui\placeholder.tga" that it will load while waiting for bigger images.
GIF in action (normal size image, the pic in the right bottom corner):
GIF of loading a big (10MB image) that takes more time:
Hope you like it!
- 7
- 5
- 2
- 19
-
Or you can skip this all and just modify that if in CGraphicTextInstance::Render to
if (m_isCursor && (ELTimer_GetMSec() / 500) & 1)
- 1
- 1
-
On 1/8/2020 at 5:16 PM, UdvAtt108 said:
I would like to correct you.
++it is more efficient because it++ need to return a copy of the object then increment itself.
And you really think the compiler won't optimize it anyway?
- 1
-
Theoretically en bloc it gives some performance gain. For example converting meshes to 16bit indices even tho sounds strange because modern cpus work faster with their native word size but the less cache miss because of the size optimization can turn the balance to the other way around.
- 2
-
It writes that out if you do that.
But here it is:
Optimizing mesh indices... Optimizing vertexes for CPU cache... Cleaning unreferenced materials...
- 2
-
56 minutes ago, HITRON said:
Good idea, Thanks for the tool.
I don't know how that sounds to others but to me sounds weird ->
Last night I was kinda playing with granny a bit and this tool was born.
haha that was intentional
- 1
- 2
- 1
-
Hey guys,
Last night I was kinda playing with granny a bit and this tool was born.
I hope it will be useful for most of you!
Optimize, change textures, convert to fbx or 3ds, etc...
Download: https://distraught.hu/download/m2dev/GR2Tool_by_Distraught.exe
Usage: Just drag and drop a gr2 file on the exe and choose what you would like the program to do.
SpoilerP.S.: Don't be surprised if the new gr2 file becomes bigger than it was, it is because this tool saves them without compression for better performance.
- 268
- 5
- 7
- 1
- 6
- 4
- 4
- 4
- 1
- 2
- 8
- 7
- 7
- 3
- 125
- 3
- 23
- 211
-
Hey guys,
I needed to be able to scroll on the ui with the mouse wheel and I thought it will be useful for others too so here's what to do.
EterPythonLib
PythonWindow.h
Add
virtual BOOL OnMouseWheel(int nLen);
after like
virtual BOOL OnMouseMiddleButtonUp();
In PythonWindow.cpp add the following function:
BOOL CWindow::OnMouseWheel(int nLen) { long lValue; return PyCallClassMemberFunc(m_poHandler, "OnMouseWheel", Py_BuildValue("(i)", nLen), &lValue) && 0 != lValue; }
In PythonWindowManager.h add
bool RunMouseWheel(int nLen);
after like
void RunMouseMiddleButtonUp(long x, long y);
In PythonWindowManager.cpp add the definition somewhere:
bool CWindowManager::RunMouseWheel(int nLen) { CWindow* pWin = GetPointWindow(); while (pWin) { if (pWin->OnMouseWheel(nLen)) return true; pWin = pWin->GetParent(); } return false; }
UserInterface
In PythonApplicationEvent.cpp override the following function:
void CPythonApplication::OnMouseWheel(int nLen) { UI::CWindowManager& rkWndMgr = UI::CWindowManager::Instance(); if (!rkWndMgr.RunMouseWheel(nLen)) { CCameraManager& rkCmrMgr = CCameraManager::Instance(); if (CCamera* pkCmrCur = rkCmrMgr.GetCurrentCamera()) pkCmrCur->Wheel(nLen); } }
Then root/ui.py and find ScrollBar class and add this function to it:
def OnMouseWheel(self, nLen): if nLen > 0: self.OnUp() return True elif nLen < 0: self.OnDown() return True return False
But you can use OnMouseWheel everywhere to listen to scrolling.
Good luck!
- 96
- 1
- 1
- 1
- 25
- 2
- 82
-
22 minutes ago, Sonitex said:
I think what @Finnael is saying makes sense. In order to achieve synchronisation of characters' movement and information you would need to send PacketAround() through P2P so it reaches other servers. Also having one master server would solve issues like spawning regens on each server or something similar (I just guessed).
I type the same for the third time now. Packet around will not send anything to the peers because other cores just really don't give a shit what happened real-time with your character. Who sees you (and this is why it sends to them) is connected to the same core as you are.
3 minutes ago, Finnael said:Yes the game can work like this because all the cores are inside one machine. When one core requires the data the other core has it gets it instantly. But in this case the cores will be in different continents.
Yes exactly.
WHAT YOU THINK HOW THE FUCK SENDS ONE CORE THE DATA TO ALL ANOTHER? THE SAME WAY AS IF THEY WERE NOT ON THE SAME MACHINE
- 1
-
Actually this is how the game now works. Don't put a map in more than one channel and its redirecting you between its cores.
-
Read again. The server only has to know eg. the position of others if they are on the same map with you (sorta kinda). What do you think, why do you divide cores by maps? They are each a running server instance.
When you start your server, you begin with the db because that application is going to receive a packet from each of the cores when they start running and distributes to the others.
If you look into the sources, you will find out that a lot of communication acts are not even sent to all the peers just what needs to be known on other channels too (like shouts).
It is completely irrelevant if those server instances are on the same machine or not if they get the address of the same db app.
-
Actually you should have no problem doing it. Basically the game only needs to sync you with players on the same map as you are. Guild stuffs are handled thru the db just like telling each cores about the others on startup. So if you target the same db for each cores even on different machines, it should work.
-
Hmm, interesting. If you can assemble a team for it you can count on me too.
-
Dear Community,
We are a soon-to-be-opened, so that still under development server in Hungary which we are looking for new enthusiastic, active and teamwork compatible members for our development team.
We prefer the Dali approach, therefore we are not seeking (self-claimed) i-know-everything guys but we eagerly wish to meet talented developers with virtue at their fields.
So what positions are free to apply?
Game designers, game economy designers, UI designers, 2D and 3D artists are always welcome.
What skills should a game designer really have?
- creativity
- playing experience with a lot of games (mostly MMORPGs)
- understanding different types of gamers, their needs and the way they work (Bartle taxonomy)
- ability to think outside the box and then sync those ideas to fit in the game
- minimal knowledge for Excel as we have all our data and game settings in xlsx files that game designers edit
What skills should a game economy designer really have?
- being good at numbers
- ability to oversee the whole game's balances
- experience at writing drops, setting values to items and monsters, besides forecasting the impact of new stuffs on the game and its economy
- defining and maintaining the values of currencies (soft and hard) and preventing inflations
What skills should a UI designer really have?
- Photoshop skills
- basic knowledge of UI/UX guidelines
- a hell of creativity
- competency to work with 2D and 3D artists to make game-ready design assets
What skills should a 2D artist really have?
- having the talent to draw graphics for the game (loading screens, concept arts)
- deftness to draw with digitalizing boards
- also a really really really lot of creativity
What skills should a 3D artist really have?
- knowledge for using 3DSMax (it's good if you can work with other programs too)
- being able to work by concept arts and by-heart also
- rigging and animating skills
You can apply or ask anything by messaging me here.
But now lets see something of the project itself too
ingame voice chat in parties
flying mounts
achievements
improved customizability
And for sure a lot of else that we didn't want to expose yet on our social media sites, like board game, puzzle event, reworked guild system, powerup card system, etc...
The server is going to open in Hungary first and after 3 months of the opening we would like to open our turkish server too.
Facebook: https://www.facebook.com/landofheroes.hu
Discord: https://discord.landofheroes.eu
-
I use the discord library. You can create lobbies with that and the game server is distributing the lobby ids between the clients. We - at Land of Heroes - use this feature for parties so that people can hear each other in like dungeons, etc.
- 2
-
14 hours ago, xXIntelXx said:
Depending on the monitor..
When you develop F2P games never can you expect people having state-of-the-art devices. By the way how about all the other arguments?
-
Rendering 250 fps when your monitor can only show 60? By the way if you run the application NOT in fullscreen mode, the window manager will sync them anyway. Only in fullscreen mode will you have the opportunity to do it on your own.
Oh and I haven't talked about the input delay it can cause. Microsoft suggests rendering and updating on 60 fps and only handling the input more times.
-
That was just an example, it's not a tutorial for that specific stuff.
But put it in CPythonNetworkStream::RecvPointChange in the if (PointChange.Type == POINT_GOLD) condition.
- 1
-
Hey guys,
It was really a long ago I did any activity on a forum so I decided to release a small but usefull class.
This can be used to place functions you want to run on every frame for a period of time with a progress on a "timeline". This can be used for example to roll the yang up or down when changing it (a normal way and not creating threads or wtf others doing) or anything else when you animating something in code.
So add this 2 files (download link at the end of this post) to your project and go to PythonApplication.cpp and find the Process function.
Add this line after like OnUIUpdate();:
Timeline::GetInstance()->DoEvents();
You can add functions like (it's an example for the mentioned yang stuff):
auto currentGold = rkPlayer.GetStatus(POINT_GOLD); auto goldChange = PointChange.value - currentGold; Timeline::GetInstance()->AddFunction(0.5f, [currentGold, goldChange](float p) { CPythonPlayer& rkPlayer = CPythonPlayer::Instance(); rkPlayer.SetStatus(POINT_GOLD, currentGold + (goldChange * p)); }, [currentGold, goldChange]() { CPythonPlayer& rkPlayer = CPythonPlayer::Instance(); rkPlayer.SetStatus(POINT_GOLD, currentGold + goldChange); } );
Download: https://distraught.hu/download/m2dev/Timeline.rar
Good luck!
-----------------------
Oh and if you can't compile it because the compiler does not find ModernSingleton then here it is:
template<typename T> struct ModernSingleton { static T* GetInstance() { static T _instance; return &_instance; } };
(just add it to like singleton.h)
- 4
- 1
- 2
- 6
-
I don't know if there's any tutorial on this, use Google. Btw what isn't working with newer gcc?
-
gcc is currently at version 9.4
why do you use such an old one? change to a new one and update from the packages: pkg install gcc
by the way i suggest you using clang as they stick more strictly to the standards and they have official support for about every platform
Disable Loading MIX, ASI, M3D... Files From Client Directory
in Programming & Scripts
Posted · Edited by Metin2 Dev
Core X - External 2 Internal
M2 Download Center
Hey again
Yesterday I was looking into mss32.dll and just found out this is the library being responsible for loading asi, mix, m3d, etc.. files. So I made a library that will hook the Miles Sound System so that it won't load unwanted files, only what is needed.
Download: https://distraught.hu/DistraughtProtector/
VirusTotal:
There are 3 files in the zip:
Open UserInterface/UserInterface.cpp and find the WinMain function.
Add this to the beginning of the function:
You have to specify the files that are enabled to load by the Miles Sound System (path, file size in bytes).
And add this before that function:
This is a callback where you get notified if the user would load a file that he/she shouldn't
You don't have to specify a callback, in that case remove DistraughtProtector::SetFileBlockedCallback(&HackerDetected); from WinMain and the client just simply won't load the dangerous files.
Here's an image what it should look like:
After that just add
to the end of WinMain (surely before the return!).
Hope you like it! If you have ideas what new features should I add to the library, let me know in the comments!