Native GML Multithreading in GameMaker - No DLLs/Networking

Discussion in 'Advanced Programming Discussion' started by MishMash, Mar 13, 2018.

  1. MishMash

    MishMash Member

    Joined:
    Jun 20, 2016
    Posts:
    379
    Hey, had a bit of inspiration today and made a quick little test to see if it were possible to create a simple multithreading system in GameMaker. I know it's a feature that many people want, and it took me about 10 minutes to get this working:

    Goals and Features:
    • Multithreading and concurrency of GML code itself without the need to use an external DLL or Networking, as these rely on moving data around and incur additional overhead.
    • Systems for managing threads, checking completion status etc;
    • Non-blocking modification of any GM variable/datastructure
    • Access to a good number of GM functions
    • Simple integration and utilisation. Currently functions as a replacement for script_execute called script_execute_async which can return a thread_id that could be used in other functions.
    • Goal is to allow the offloading of heavy tasks to separate threads as to not block the main thread. Or improve quality of life by having routines such as level generation not impact performance
    • Ability to set maximum number of cores an application can use to avoid consuming too many system resources

    Video:
    This video is a discussion and pratical example of the system


    Method:
    By injecting a small amount of C++ code into the YYGML.h header which gets included in every GM YYC project, and a few replacement C++ scripts for generated GM script files, we can achieve this system with relative ease, taking advantage of the simplicity and clean interface of C++ 11 threads.

    Pretty excited for the potential and simplicity of this. Naturally, GM doesn't enforce any concurrent code design patterns such as locks, so it would be entirely up to the user to ensure their code was thread-safe. Though, given the nature of threading, most processing related things just work, though you naturally will get bugs if two things try to use/modify the same thing. It is however ideal for Embarrassingly Parallel problems where the data being modified in each instance is completely independent between threads.

    In order to have a good idea of what is going on, I recommend watching the video.

    Disclaimer:
    As this involves modifying generated C++ code, it doesn't fall under any support for GM so if you do try any of this out, do so at your own risk.

    I'd like to try and start a discussion about the utilisation of this, and whether it is something people would consider using, or ways in which this system could be designed differently to cover a better use case. Note that given how this is achieved, there is a user practicality limit, so I would want to limit the system functions such that:
    - Generated GM script files do not need to change once compiled once. (No change as a reuslt of unrelated changes elsewhere)
    - Minimal modifications to shared GM header, which do not have any impact on ordinary execution.
     
    Binsk, Roa, Leschge and 11 others like this.
  2. icuurd12b42

    icuurd12b42 TMC Founder GMC Elder

    Joined:
    Apr 22, 2016
    Posts:
    1,839
    Interesting hack. the issue I see is reading data you write inside the script from outside, like your code is doing reading of the grid in the draw is not safe. if the 2 thread are trying to access the same data there will be a problem...

    Thread synchronisation would be an issue long story short. but it could be resolved using old school thread read sync trick since you dont have thread locking/blocking mechanism

    global.ready = 0;
    global.data = 0;
    in thread
    //do struff to data
    repeat(10000)
    {
    global.data+=1;
    }
    global.ready = 1;


    in regular code
    if(global.ready !=0) (may be 1 or garbage if thread is mid write), either way it's ready
    {
    var thereadyData = global.data;
    }

    I'm not sure by today's compilers if there is precautions in the compiled code to prevent 2 threads accessing the same memory at the same time that would cause an exception. we did not have thread safe stuff in the old days and that's how we did it... but this method may no work if the compiler has thread safety mechanisms. I don't know is what I'm saying.

    @Mike
     
    Last edited: Mar 14, 2018
    MishMash likes this.
  3. MishMash

    MishMash Member

    Joined:
    Jun 20, 2016
    Posts:
    379
    @icuurd12b42 From my experience with C++ 11, with regard to actual data modification, or modifying of overlapping values, i've never actually had any objective issue. No crashes, just whichever thread happens to run second will overwrite any previous result. Cache's are also very robust these days. C/C++ are also very raw and they tend to let you do whatever, it's just up to you to make algorithmic guarantees about the safety of your code. For example, as you suggested, just imlpementing a ready flag to serve as a lock.
    I think a potential use case here is simply for when threads all do their own things and are quite disjoint. i.e. there is no overlapping data, but it is simply a way to speed up processes, or offload them.

    The potential for crashes would come more from thread abuse, i.e. having one thread modify the contents of a list or remove/add elements whilst another is iterating through. Though all of these things can be avoided if you organise your code well and exercise discipline.

    In my project for example, chunk generation is contained within a function, and that function only writes out data to a single grid. This grid cannot be used by anything else in the game until it is fully generated, at which point a generated flag is set to true. The only other data is read-only input data, so in that case, it should be okay.

    At university, I had a High Performance Computing module which had heavy focus on making code run as fast as possible, using a variety of techniques, mostly OpenMP which was a wrapper to simplify the process of distributing code across different threads automatically. In practise, I have also written applications using "unsafe" multithreading which I know myself to be okay, and generally, there don't seem to be exceptions, it just tries to do what it thinks, so if there is a value, it'll return the value it finds at that moment, however it can mean if multiple threads are trying to increment a value, the end result will be nonsense as the value stored in registers will be different for each and they'll end up overwriting each other. Though I don't think modern C++ actually crashes, there may be a flag set, or it may depend on the datastructure.
     
  4. Lonewolff

    Lonewolff Member

    Joined:
    Jan 8, 2018
    Posts:
    1,207
    Yeah, if I remember rightly, there is still issues around this if you don't lock the variables.

    Things get funky at that kind of level as you are playing with things in the CPU cache and not the RAM itself (if my understanding is correct). So, while you think you have changed a variable to something else, the other thread can still be playing with another different value.

    I had all sorts of issues with this a while back and the only way I got around it was to lock the variables. Had no crashes or anything, just not the results I was expecting.
     
    MishMash likes this.
  5. MishMash

    MishMash Member

    Joined:
    Jun 20, 2016
    Posts:
    379
    Just did a bit of extra reading and apparently (as I thought) the program wont crash, but you will just get race conditions and garbage values as expected if you try to write to the same value at the same time. People only talk about safety with regard to expectation of how something works, rather than how it actually works.

    So, as long as you are careful with when/how you modify values, you should be okay. This may mean if you are trying to do a sum in parallel, each thread maintains its own sum value, and then once both threads have finished, you sum up those sums in parallel.

    Though, I will throw in a tutorial on how to create a lock/concurrent programming techniques in general, as it'll likely be useful and not too difficult to achieve in GM itself.

    (The same may not be true for mobile platforms, but currently, I'm only interested in desktop applications).
     
    Lonewolff likes this.
  6. Lonewolff

    Lonewolff Member

    Joined:
    Jan 8, 2018
    Posts:
    1,207
    Yep, pretty much as I found in practise :)
     
  7. icuurd12b42

    icuurd12b42 TMC Founder GMC Elder

    Joined:
    Apr 22, 2016
    Posts:
    1,839
    from my experience. as long as one thread is doing all the writing and the other is doing only reading, the only issue is that the reader may get garbage data upon reading, hence the flag to synchronize, which you dont care if the flag is truely set to 1 or garbage; mid write
     
  8. GMWolf

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,442
    A simple lock will not be enough: the lock itself could get race conditions.
    I dont 100% remember my OS course, but there was talk of using Semaphores to solve the problem.
    They could easily be written in c++ (or use the standard library) and wrapped for use in GML.

    The important thing is to make sure that operations on the lock are atomic. A simple boolean variable will not be atomic
    Code:
    if (!lock)
       lock = true;
       dostuff();
       lock = false;
    }
    
    A checks lock. => open
    B checks lock => open
    A closes lock and does stuff
    B closes lock and does stuff.
    With multitreading, this can totally occur.
     
    Ampersand, MishMash and Lonewolff like this.
  9. Lonewolff

    Lonewolff Member

    Joined:
    Jan 8, 2018
    Posts:
    1,207
    Yeah, I use semaphore variables quite a bit.
     
  10. MishMash

    MishMash Member

    Joined:
    Jun 20, 2016
    Posts:
    379
    I can't actually remember what they were formally called, but in my Concurrent Computing/operating systems unit we had something similar, though I remember the dining philosphers problem which involved a similar resource allocation problem, and in this case, the solution was to avoid a deadlock, however the solution applies. In this case, you introduced a third party (a waiter) who would see who had expressed interest in the resources (forks on the table) and then allocated them. So no thread took responsibility itself for wanting a variable, it would first express interest in a variable, and then wait until it had that variable acquired.

    For example (PSEUDO CODE):
    Code:
    var lock_id = lock("some_var"); // Express interest in some variable
    while(true){ // Block/keep trying
        if( global_lock("some_var") == lock_id ){ // If the global system has allocated that variable to us
              // do stuff
              release_lock("some_var", lock_id); // Say we are no longer interested in that variable
              break;
        }
    }
    Since none of the threads control how global lock is allocated directly, there is no overlapping of locking. (As a practical solution, one thread would be given responsibility of being the resource manager, lets say thread index 0, if you didn't want to allocate a specific separate thread for managing resources.)
     
  11. GMWolf

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,442
    I remember semaphores and mutex.

    I think what you describe is known as a spin lock, but i'm not sure.

    I still have my OS notes from last year, I'll have to read through them again.
     
  12. icuurd12b42

    icuurd12b42 TMC Founder GMC Elder

    Joined:
    Apr 22, 2016
    Posts:
    1,839
    OK, now make some code where the movement is in a thread and the draw in another :)
     
  13. MishMash

    MishMash Member

    Joined:
    Jun 20, 2016
    Posts:
    379
    Image:
    [​IMG]
    So, given that the while loop runs stupidly fast I initially used the _pressed variant, and given GM resets the keyboard state/polls for it on its own accord, keyboard_clear needs to be specifically called to create the same behaviour.

    However, I think it is important to determine a list of practical/non practical use cases for a system like this. As an initial guess, i'd imagine a good example of things NOT to mess with would be:
    - Any internal GM system that maintains its own internal state and has its own processing , Audio, images, networking, etc; OR any GM system that has background code running between events that the user does not see. This includes collisions.
    - Anything related to the graphics pipeline and/or rendering to the screen. DirectX 9 does not support multi-threading natively.

    Though all of these caveats would be the same for any engine. Though it'll be important to outline any use case outside of data manipulation, and without employing good concurrent principles, could lead to side effects within your code. For me personally, i'd simply limit this use case to heavy lifting scripts that tend to take a read-only/simple input and return an output, or fill in some independent data.

    Good examples of use cases:
    - Pathfinding (Path calculations on static grid)
    - Simulations, such as fog of war, fluid dynamics.
    - AI thinking, for games with more complex AI such as chess, so that the player can continue interacting with the game or doing other things whilst the AI is making its move
    - Compression/conversion of datastructures for networking (so that if you have a particularly large clump of data that needs sending, you can build it into a buffer without blocking up your whole game)
    --- Similarly, this can apply for saving and loading (wouldn't recommend actually calling file IO from a different thread, but you could build the buffers in a different thread and then simply save them from the main, as the saving is generally the fast part.
    - World/Level generation -- This would again allow it to avoid having an impact on player performance and could similarly allow you to start the game earlier whilst continuing to generate things afterwards.
    - distributing similar algorithmic tasks (that could have an impact on performance) such as sorting.

    Generally, games wont have loads of threads. If your game is running so slowly that it needs threads for common game features like enemies, then there is a problem with the design. However, the main benefit I see is more to do with offloading infrequent tasks, and just allowing a game to utilise more of a players machine. This can be especially relevant on weaker machines which may have multiple cores, but a low per-core clock speed. Another example in my project is that in order to make pathfinding fast, I had to build a pathfinding request system where objects submit requests for paths and a general pathing control object processes paths continuously, though limiting the number of operations per frame as to avoid lagging the game. An object will then wait (normally only a few frames) to get its path.
     
    nb109 and icuurd12b42 like this.
  14. Lonewolff

    Lonewolff Member

    Joined:
    Jan 8, 2018
    Posts:
    1,207
    While DX11 on GMS is single threaded, I have found that it is trivial to turn on multi-threading on the graphics pipeline and play around with it (if you are particularly careful).
     
    MishMash likes this.
  15. GMWolf

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,442
    I though dx11 was inherently single threaded, and dx12 was needed for paralelle draw calls.
     
  16. Lonewolff

    Lonewolff Member

    Joined:
    Jan 8, 2018
    Posts:
    1,207
    Even DX9 had the capability to be multi-threaded, it just wasn't very good.

    DX11 handles MT much better, but for absolute control DX12 is the go (but massive overkill for most people - myself included).
     
  17. icuurd12b42

    icuurd12b42 TMC Founder GMC Elder

    Joined:
    Apr 22, 2016
    Posts:
    1,839
    wait, x+=10... the instance context is maintained?
     
  18. MishMash

    MishMash Member

    Joined:
    Jun 20, 2016
    Posts:
    379
    Yessir, given how YYC works, "pSelf" and "pOther", the pointers to the GM instances, are always passed into any function/script that gets called, giving you access to the context of the instances. Whatever code you can run in a normal GM script, you can get to run in a seperate thread. (Whether that code then works safely is a different matter, as i expect certain functions to behave oddly, such as collision check ones may come out wonky as those will depend on some processing being done by the main thread, and having that run whilst the underlying collision map is being updated might break something)

    So basically any script in GM has two implicit arguments that are self and other, and all non "var" declared local variables are assumed to belong to the "self" instance.
     
    Lonewolff likes this.
  19. Ampersand

    Ampersand Member

    Joined:
    Jan 30, 2017
    Posts:
    216
    It is always fascinating to learn bits like this about how the IDE and the compiler itself actually work... Wish I could contribute anything to the discussion, but what I do understand is only giving me vivid flashbacks of an Intro to Operating Systems class I sat in on -- it's really making me wish I had dove in rather than shying away from this sort of stuff.

    One has to feel a bit like a frontiersman exploring ideas like this!
     
  20. icuurd12b42

    icuurd12b42 TMC Founder GMC Elder

    Joined:
    Apr 22, 2016
    Posts:
    1,839
    collision functions should work, at least if you dont have the fast collision system enabled as they basically rely on the position scale and angle and stuff... Hmm. I have a step emulator I wrote almost a decade ago which basically uses event_perform to simulate stepping in a loop. I wonder. basically

    loop{
    with(all) {xprevious = x; yprevious = y; event_perform(step, step begin)}
    with(all) event_perform(step, step)
    with(all) with(all) if(intance_place(other.id...)) {event perform twice, once with this and once with the other involved)}
    with(all) event_perform(step, end step)
    }

    not sure what would happen but it's something you crazy kids can try...
     
  21. MishMash

    MishMash Member

    Joined:
    Jun 20, 2016
    Posts:
    379
    I was unsure whether collisions were made faster by some internally updated grid. I know when I wrote my own game engine in the past, the only way I could achieve fast collisions was to maintain a quad-tree which was updated at the start of each step using the bounding boxes, or bounding spheres of instances. This reduced collision complexity by instantly being able to only test against things in the corresponding quadtree sections you needed to test, rather than the whole game world. I imagined GM may be doing something similar internally, and that functions like place_meeting used this to reduce the number of instances needed to test against. (Given that it may need to build this quadtree to fire off certain collision events anyway). I guess the only way to know is to try it out :p

    Could probably also get away with creating an event_perform_async function, but I think that's asking to be abused :p

    Edit: On a progressive note, i'm going to have a look at finishing up and uploading this first little test tomorrow once i've finished my work for the day. I don't expect it to be practically useful for a bit, though I think time is needed to experiment with things like this. The only long-term intention I want from this is to be able to do include some additional optimisation for my own project nearer to its final release.
     
  22. Tthecreator

    Tthecreator Your Creator!

    Joined:
    Jun 20, 2016
    Posts:
    757
    Wow I love this. Great work!
    Though I guess this only works on windows YYC?

    Anyways, I could see this used mostly for having a script with some intensive process be separate of the normal thread used for drawing.
    Like for example you have to generate a world and want to show the user a loading bar that runs at 60 fps.
    Previously you had to just put your script in a step event and just hope it wouldn't take longer than 1/60th of a second.
    This system would make just implementing some of those things really easy.
    Using it in such a way doesn't give you any race conditions or anything. But it only makes life easier instead of giving a big performance benefit.(since the entire task is still in one thread)

    This is going to lead to a lot of problems for people who don't know what they are doing.
    Therefore, it probably wouldn't be fully safe for commercial projects if one just started out using threads without having dealt with these kind of threading related bugs before.
    Still this is extremely useful to those who do know how to use this properly.

    I've actually got this game idea and if I can't figure out the maths I'll have to simulate everything instead. In the latter case this would be so useful.
     
    MishMash likes this.
  23. kupo15

    kupo15 Member

    Joined:
    Jun 20, 2016
    Posts:
    770
    First off this seems fantastic and exciting! Great stuff!

    This would be what I would be using this for, graphics mainly. What kind of graphics things are you recommending against with this? I would like to use MT to load new graphics and unload no longer needed graphics in the background to avoid loading screens altogether. Surely this should be an ok thing to do, right? Just make sure not to reference any new graphics until the thread is finished loading everything. And I would imagine unloading in the background is also safe because you wouldn't be referencing anything you aren't using anyway
     
  24. MishMash

    MishMash Member

    Joined:
    Jun 20, 2016
    Posts:
    379
    Rendering will break because GM manages batching and other things internally. The reason loading of resources on a separate thread is dodgy is because internally, DirectX builds an object for that graphic and submits it to the GPU. Given that GM manages this, there is no means of using GM's specific systems (i.e. what it does internally) on a separate thread. It might work, it may not, however the important thing to remember is that its not just loading things into memory, its the transfer between CPU and GPU memory + vice versa, and this is managed by the directX pipeline, which in DX9 is primarily single threaded, and calling pipeline functions from another thread (which GM will do) causes a crash.

    For resource loading, if you represent your filepath as a URL, you can load sprite asynchronously already: https://docs.yoyogames.com/index.ht...reference/game assets/sprites/sprite_add.html
    Many other asynchronous functions already exist in GMS to save/load resources and data for buffers, therefore you are probably better off using those for that sort of purpose.

    The main benefit of threading in this context is likely going to be algorithmic improvements. This does include data preperation, for example the building of a vertex buffer could likely be done in a separate thread.
     
  25. kupo15

    kupo15 Member

    Joined:
    Jun 20, 2016
    Posts:
    770
    Wait, so you are saying GM already supports the ability to prefetch sprites into VRAM without the stutter you experience from doing so using the async events? But that it has to be retrieved from a website instead of the included folder or IDE? What if I want to load sprites from the included folder and prefetch them into VRAM and do so without the stutter? Or what if I want to do a texture flush or prefetch assets from the IDE without having a stutter occur? I thought that is what the MT was needed for....
     
  26. MishMash

    MishMash Member

    Joined:
    Jun 20, 2016
    Posts:
    379
    Into VRAM, no. As said before, DirectX 9 is single threaded, and regardless, there is a fixed pipeline communicating between the CPU and GPU. However, upon importing a sprite, it still has to get processed on the CPU first. The loading process of a PNG for example involves converting it into an array of pixels. This is managed internally. Regarding how long it takes things to be sent to the GPU, this depends. Normally, modern GPUs have incredibly large bandwidths (of the order of 200GB/s+) so sending graphics to the GPU should never be too slow, unless you have loads and loads of graphics, at which point a stutter may occur.

    Think of it this way, the process is split into two steps:

    1) A "sprite" resource is loaded from HDD into CPU RAM
    2) When you want to render a sprite, if it is not already loaded onto the GPU, it will be sent from CPU RAM -> GPU VRAM. Once it is in VRAM it can be quickly rendered.

    The loading of a sprite only deals with step 1. Step 2 is not necessarily executed until your first render, though this depends on your project settings, and the settings may differ for other sprites.

    Whilst the asynchronous functions only work with file requests, I think you can get a sprite to load asynchronously by using file:/// in front of the filename. However it is worth noting that asynchronous functions aren't necessarily multi-threaded, they just make up events in an event loop. It just means that it doesn't stop execution of your current task. (Though GM doesn't provide specific information on this).

    I don't want to diverge this thread too much, but sprite_prefetch and sprite_flush only control when the data is sent to the GPU. A stutter from this is unavoidable, because its to do with a pipeline bottleneck in the rendering thread.
     
    Tthecreator likes this.
  27. GMWolf

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,442
    The key is that stuttering during a loading screen doesn't matter, but stuttering during game play does.
     
    kupo15 likes this.
  28. MishMash

    MishMash Member

    Joined:
    Jun 20, 2016
    Posts:
    379
    Yeah I know, but kupo seemed to know about the existence of this functionality and was talking about how dynamically loading/unloading of resources mid-game was causing problems.
     
  29. kupo15

    kupo15 Member

    Joined:
    Jun 20, 2016
    Posts:
    770
    Sorry if this is derailing it, but I think this still ties back into learning the limitations of MT and at least can held debunk any myths other users might have with it like I do

    Ok true, things don't have to be sent to the VRAM straight away and the two parts is a good visual. So if loading a sprite into memory is purely a CPU function only, does that mean that this step in the process only could be handled via MT?

    So then how do consoles manage to swap out textures during gameplay without a stutter like Wind Waker for example? Or does WW still stutter during the VRAM process but its so tiny its not noticeable? I thought this was MT at work...

    On a side note, are animated loading screens actually disguised stutters? As in its the main thread that is stuttered swapping out resources but the second thread is using the draw event to draw an animated texture that was already loaded into memory instead of what I thought which was using the second thread to swap resources while the main thread remains unstuttered? Kinda like how you showed off you can draw moving the text around while still doing things in the background? Can you play the game on the second thread with resources that are already loaded while you load new resources on the main thread?

    EDIT: A better example would be how does Breath of the Wild have zero load screens during the massive overworld yet no stuttering or perceived stuttering? Surely it must be swapping out textures throughout instead of holding all the textures in the overworld at one time
     
    Last edited: Mar 14, 2018
  30. MishMash

    MishMash Member

    Joined:
    Jun 20, 2016
    Posts:
    379
    To take a slightly different approach, there are many answers to this question:

    First of all, different graphics API's have different restrictions on what can/can't happen. DirectX 11 for example does support multi-threading, and DirectX 12 makes multithreaded functionality very accessible (This is part of what contributes to its large speed up over DX11).

    Secondly, most games inherently have a number of independently running threads from the get go. Normally, it is common to separate out the simulation thread from the rendering thread. You may also throw in a resource manager thread too. Having a setup like that instantly gives you more flexibility because all of the stages are disjoint. (Whereas in GM, the limitations come from the fact that both simulation and rendering happen in the same thread, so you run into issues when trying to separate the two). So in AAA games, the simulation thread never touches resources, similarly, the resource management thread handles dynamic loading of assets, and the rendering thread would only then be allowed to use a resource once it has been fully loaded.

    In my experience, it also seems to take a lot to get the game to stutter from the loading of textures onto the GPU. Generally, it only seems to be that initial load that is really slow (HDD to CPU), but this makes sense in a way, as the interface between a CPU and GPU is 1000x faster than that between a CPU and a HDD. Which is good news, because the loading to CPU should be something we can get around. Though using the multi-threading for this may not work given that sprite_add would need to manipulate some internal GM sprite datastructure, and having two threads mingling with the same data could be messy. So i'd say I don't think this specific Multi-threading will work without a stutter given that the resource management and rendering both share a same thread, and I can't do anything to change that without use of a separate DLL for rendering.

    I'd give the async loading thing a try though. I've never done it, but that seems like the best bet.

    Edit: Regarding loading screens, normally they will hide stutters, however again, in conventional games, the rendering thread is free to do what it wants and will rarely block. It will simply display the progress being made by a resource management thread. AAA games also are not perfect. GTA V can stutter a fair bit if you are going really fast, Watchdogs was worse for it. Most openworld games end up having quite slow movement however, so they can safely distribute loading evenly as they aren't forced to load 100s of textures in a single frame.
     
    kupo15 likes this.
  31. kupo15

    kupo15 Member

    Joined:
    Jun 20, 2016
    Posts:
    770
    Oh I see, that explains why you said its impossible to avoid a stutter from VRAM loading. Not that its impossible in general but in GM it is because the architecture of how GM's Engine is built prohibits that naively. So that means we will never be able to get to see a true GTA style GMS game without stutters unless you use a DLL. That's the difference between what you are trying to do and the other MT thread I saw that uses a DLL. His application would be more in line with this sort of thing for me then.

    And this HDD to CPU only occurs from external files I believe, not if you already include them in the IDE which makes external loading slightly longer than IDE resources unless I'm mistaken. My game is one where it takes a lot so stuttering is unavoidable on GMs native single core design. Luckily my game doesn't require seamless loading, it just would be nice to have. Waiting 3 seconds to load a match (currently) isn't that bad to wait. It might end up being closer to 5-6 when the game is done unless I come up with tricks to cut that down. (one character's sprites alone takes about 2 seconds currently)

    Thanks so much for taking the time to explain this to me!
     
  32. GMWolf

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,442
    There is a reason why companies still develop in house engines. Even engines like Unreal still focus a lot on the idea of Artists using them, not programmers.
    You would be surpirsed at the stuff you can do when you dont abstract DX or OpenGL away!
     
    Last edited: Mar 14, 2018
    kupo15 and MishMash like this.
  33. Lonewolff

    Lonewolff Member

    Joined:
    Jan 8, 2018
    Posts:
    1,207
    Should be able to achieve GTA in GMS with your eyes closed.

    [​IMG]
     
    kupo15 likes this.
  34. Juju

    Juju Member

    Joined:
    Jun 20, 2016
    Posts:
    412
    "Fast collisions" in GMS1 use an R-tree. GMS2 uses the same system as the default, and only, option.
     
  35. kupo15

    kupo15 Member

    Joined:
    Jun 20, 2016
    Posts:
    770
    Ah I see, that makes sense. I didn't know that even Unreal is just as limited in some ways
     
  36. GMWolf

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,442
    The thing with Unreal is that it *does* allow you to have access to lower level API's. But at that point you are better off with a bespoke solution.

    Back on topic though:
    How does MT behave with instance and asset creation in GM?
    I'm guessing that if you are not careful, to simultaneous calls to ds_*_create could return the same ID?
     
    kupo15 likes this.
  37. HammerOn

    HammerOn Member

    Joined:
    Jun 22, 2016
    Posts:
    92
    Isn't it against eula's 4.ii term?
    It would be fun to play with but if I can't publish something with it...
     
  38. Lonewolff

    Lonewolff Member

    Joined:
    Jan 8, 2018
    Posts:
    1,207
  39. HammerOn

    HammerOn Member

    Joined:
    Jun 22, 2016
    Posts:
    92
  40. Lonewolff

    Lonewolff Member

    Joined:
    Jan 8, 2018
    Posts:
    1,207
    All of the above applies to that link.
     
  41. rIKmAN

    rIKmAN Member

    Joined:
    Sep 6, 2016
    Posts:
    4,525
    Your own game is neither "Publisher Property" or a "YYG Platform" which is what is stated in the EULA 4.ii clause.
     
  42. Lonewolff

    Lonewolff Member

    Joined:
    Jan 8, 2018
    Posts:
    1,207
    The exe is the YYG runner. Which is very much "Publisher Property".

    Even if it were your own game, as such. You are still not allowed to decompile or reverse engineer it, as it is not your engine.
     
    rytan451 and rIKmAN like this.
  43. rIKmAN

    rIKmAN Member

    Joined:
    Sep 6, 2016
    Posts:
    4,525
    Yeah fair point re: the runner, can PIX be called a reverse engineering / decompiling tool?

    Everything I've seen is to do with profiling, performance tuning and debugging, which isn't really the same thing as what the EULA is talking about (in practical terms) and which is what Mikes article also refers to.

    It'd be a bit odd to have a blog article giving a tutorial on how to break the EULA, but as we know the EULA can be a little ambiguous at times.
     
    Lonewolff likes this.
  44. Lonewolff

    Lonewolff Member

    Joined:
    Jan 8, 2018
    Posts:
    1,207
    For sure.

    You can strip out the compiled shaders, geometry, and all sorts of gear in there.

    90% of what you see in the Pix output is the GMS internal 'secrets', very little in the render cycle actually belongs to the code that you type in.
     
    rIKmAN likes this.
  45. rIKmAN

    rIKmAN Member

    Joined:
    Sep 6, 2016
    Posts:
    4,525
    So technically the blog is just using the profiling tools in PIX, and so isn't breaking the EULA (even if that's possible with it)?

    I'll have to check it out sometime, I remember reading an old thread where you dissected the the render cycle with Russell that was a bit over my head, but an interesting read.
     
  46. Lonewolff

    Lonewolff Member

    Joined:
    Jan 8, 2018
    Posts:
    1,207
    Technically yes. But you have to disassemble/reverse engineer, in order to do this.

    Either way, I am sure that YYG would be loving that people are pushing all sorts of boundaries with GMS. What MishMash has going on here is magic!
     
    rIKmAN likes this.
  47. GMWolf

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,442
    I made a tool to extend the GML language for GMS1.4 and got shutdown.
    Probably because it would have made GMS2 redundant.
     
  48. Lonewolff

    Lonewolff Member

    Joined:
    Jan 8, 2018
    Posts:
    1,207
    Geez, really? Where you told to stop?
     
    Last edited by a moderator: Mar 16, 2018
  49. GMWolf

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,442
    It messed with the GM compiler so I asked if they where ok with me releasing it..and if it was tevhntechni against the EULA.
    I should not have asked.
     
    Lonewolff likes this.
  50. Lonewolff

    Lonewolff Member

    Joined:
    Jan 8, 2018
    Posts:
    1,207
    That's pretty rough. If someone wanted to improve/expand things, I would have thought they'd be supportive that you are pushing the engine to greater limits.
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice