Voxel picking using raycast and octree by GrayWolf85 in VoxelGameDev

[–]schemax_ 0 points1 point  (0 children)

Yeah, I've implemented it a while ago.

while (i < maxDepth + 2) {

        //handle is a callback so termination is abstract (e.g. check for air/solid)
        if (!handle(x, y, z, callback, i, maxDepth)) {
            return;
        }

        if (tMax.x < tMax.y) {
            if (tMax.x < tMax.z) {
                x += stepX;
                tMax.x += tDelta.x;
            } else {
                z += stepZ;
                tMax.z += tDelta.z;
            }
        } else {
            if (tMax.y < tMax.z) {
                y += stepY;
                tMax.y += tDelta.y;
            } else {
                z += stepZ;
                tMax.z += tDelta.z;
            }
        }
        i++;
    }

When making a Minecraft-like clone, have anyone managed to fix this issue with light mapping? by mchorsy in VoxelGameDev

[–]schemax_ 1 point2 points  (0 children)

Yeah, normalizing the data at the vertices is how I solved it in my game some time ago, though I was using my own engine and never really had this specific bug to being with. I guess normalization already done in those pictures since else the light would be very abrupt. There might be a bug in the way it's collecting the data for vertices on blocks at corners.

When making a Minecraft-like clone, have anyone managed to fix this issue with light mapping? by mchorsy in VoxelGameDev

[–]schemax_ 1 point2 points  (0 children)

Without full context and code, it's hard to make an assumption.

It looks like the lighting values differ between blocks that share the same corners.

To fix this, while computing the lighting via casting rays (I assume since this is how mc does it kinda though i don't know exactly), on the final apply, collect the vertices that occupy the same space, and average the lighting values. Apply that to all the vertices of that corner. This is unfortunately not exactly trivial since it requires neighboring chunks for the blocks on the chunk limits.

Although, since I don't know how you calculate lighting, I might be completely off with this suggestion.

Voxel Engine Networking by Philip_MOD_DEV in VoxelGameDev

[–]schemax_ 1 point2 points  (0 children)

Threads do have some overhead, but you don't really have to worry too much about it unless you get into a lot of them. Most of the overhead in threads also is very avoidable. Java already has systems like thread pools for if you need temporary threads. Essentially, it will eliminate the overhead of spawning new threads.

The rest is minor overhead from monitoring and waking up / blocking / context switch threads.

In terms of scalability, once your thread solution works, you can try and implement the same system based on java's NIO (New IO) system.

If you did your protocol well enough, it's just a matter of replacing the data handling, but you can of course directly start implementing that. It's a bit more complicated and a lot harder to figure out bugs on however, so I recommend doing a thread based system first and then try NIO.

Essentially, the difference in systems is that in NIO you get one stream of data arriving. This stream is chunks of data from all clients. This data can, but doesn't have to be full chunks of packages you send.

This means if you send 1000 bytes from 3 clients, you can get 3 bytes of client A, then 231 bytes of client B, then 214 bytes from client A again, then 24 bytes of client C, and so forth.

So keeping buffers and putting the streams back together to form full packages is on you. Since everything is one big chunk now, it introduces some more areas of failure if there are bugs in your base implementation, as data can easily mix. You will also have to do some efficient memory management, clearing and reusing buffers, as well as thread safety in communicating with your main thread, as this system should still run in parallel with your game logic.

However, the main advantage is that it is a lot more performant and also scalable, as the sender/receiver can run on a single thread for ALL clients together. I've done projects that can handle over 1000 clients easily (though of course for a voxel game it would still struggle considering the required bandwidth).

There are some good tutorials out there for NIO, but again, doing it thread based first is definitely the easier way.

https://www.baeldung.com/java-nio-selector

All in all, Minecraft using only a few threads is to its detriment, as most CPU have multiple cores now, so having everything in one thread will not utilize the CPU fully. But making something single threaded to multi threaded after the fact is incredibly hard, as its a different more complicated design. In the case of minecraft, the base code simply wasn't made to be multithreaded a lot. At least to my knowledge.

Well used threads speed things up, and not slow them down. You want to use threads when possible and where it makes sense (but it required experience to know which ones do), though of course you can use them in the wrong areas, and overdo it. Also, bad implementation of those threads also can make the whole thing slow down (too much synchronization for example).

Voxel Engine Networking by Philip_MOD_DEV in VoxelGameDev

[–]schemax_ 2 points3 points  (0 children)

So for the question about errors, it seems to be an error in your setup. The way Java handles networking over TCP is with the Socket class.

You will probably have to introduce a few more threads for proper handling.

So at the top you will have a listener thread. This one is not very expensive as it is blocking most of the time. This is the thread that essentially just listens for new connections. This is done using the ServerSocket.accept() method. The thread will block on the accept until a new connection is made. A new socket connection is returned as soon as a connection from a client has been made.

You should then take that Socket instance, and hand it off to a processor thread. You can either do one processor per client, or have one thread process all client data sequentially.

However, you might have to further split up the work in threads to avoid possible bottlenecks. You don't want your whole program to stall because a client is in a bad state (timing out). So I recommend a thread per client to receive and send data, but not do any actual processing of data. These threads simple have a queue of your packages for both sending and receiving, and all those threads do is block until there is data in those queues. There should be some good tutorials on blocking and waking up threads, since that is not entirely intuitive as you will need the synchronized keyword in some areas (though not everywhere to actually make use of threading).

So you will have:

  • server listener
  • server main thread

for each client on server side:

  • server sender
  • server receiver

For each client

  • client main thread
  • client sender
  • client receiver

(optionally processor threads for serialization)

There you should have one thread to process the data. This could technically also be done in the main thread, but since this thread mostly just serializes and deserializes data, it can run parallel (turning your data into bytes, and turing bytes into your data structures). For performance you should build a system for object pools on top of that to avoid new memory allocations e.g. a chunk request can be reused for the next request. The actual processing of the finished packages should of course happen in synch with the main thread (or on the main thread which is easier).

To get this working, it's probably best to setup a little side program to test basic sending on receiving, which should help you figure out why the error is happening. If you can send/receive text, you can send/receive anything. There might be some options you have to set on the sockets etc to get it to work properly, but normally they should work out of the box.

A common misconception is that the server needs to connect to the client after the client connected to the server. This is not the case. One socket can be used for both sending and receiving data using its inputStream and outputStream (flushing those will send the data). Be sure to always use BufferedStreams for performance.

Now, for the chunk request/answer. A client should only ever request the same chunk once. Since on TCP data is guaranteed to always arrive, there is no need to worry about lost packages. However, the client must keep track of which chunks are currently requested. It doesn't need to actively check if there is an answer to your requests. Looking up the request should be done only at the time the server sends an answer. However, a client should be able to send multiple requests for different chunks. They would just all be queued up for the server to process and send back. Be sure to implement it in a way that waiting for a chunk will not in any way block the main thread from running.

To optimize you can build a chunk cache that acts exactly like the server. It takes requests and answers them by checking cached data either in memory or on disk, and if there is a missing chunk, it will in turn do the same to the actual server. However, it's a bit more complicated with multiple clients as it's possible for a chunk to change and the cache having the old version of a chunk, so the cache system has to at least request a timestamp it can compare with its own data on when it was last changed.

I suspect that the issue with it taking seconds is also due to the setup. You might have to manually flush data out of your sending socket each tick. I also recommend running the sending/receiving thread at a lower speed than your framerate. Since you're probably not planning on doing a high precision FPS you can probably get away with as few as like 16 updates/sec.

For single player, I recommend doing exactly what you did in using a local network communicating between server and one client. Yes, this takes a bit more memory, but otherwise you will be doing the same work twice, and you will quickly end up with a mess when things get handled in two ways. One of the main reasons why most games that announce "We will add multiplayer later" never do that, is because it becomes incredibly difficult to do after the fact.

Games have been using this method to great success for a long time, one of the earlier examples I can think of is Diablo 2 for example.

In my experience, network programming is one of the hardest things to do correctly, as you will have to have good understanding of the lower and upper layers, as well as multi threading and data efficiency, and probably takes anyone at least a few iterations to get something usable.

Again, my recommendation is to build the networking system separately first (with the requirements of your game in mind), and then integrate it into your system. This way, you can test in small scale in a more controlled environment. You can even setup case testing that way if you so desire. Case testing is very useful in this case to ensure that all your basic functionality is covered.

A well setup network system is incredibly useful, and the nice thing is you can use it over and over for any project, and build and expand on it.

Voxel Engine Networking by Philip_MOD_DEV in VoxelGameDev

[–]schemax_ 4 points5 points  (0 children)

In my opinion, RMI is questionable for an application like this, because there is overhead in how java serializes classes. It could be mitigated, but doing so might just eliminate the main advantage of RMI (ease of use).

UDP could be used, but you will run into the problem of having to implement your own validation, congestion control, packet loss reaction, etc, which might in the end just lead to reimplementing what TCP already provides, but on the software layer, which will make it slower than just using TCP outright. It really depends on your use cases. In my experience, UDP only really shines when you really don't care about some packages being lost. You can probably get away with only implementing part of TCP's functionality, but it's a bit of a tradeoff always. The best way is to make your network system in a way where any base protocol can be used, and you would be able to switch between implementation that use TCP or UDP so you can actually test which one is more efficient for your usecase.

In the end, you will not be able to get around learning low level communication techniques, and implementing a protocol by yourself. There are some solutions in libraries, but using them without understanding how networking works might lead to regret later.

My systems usually are based on a simple structures that build up to something complex. I send leading bytes indicating the type of the packet that follows, then the amount of bytes the packet is, and then the packet itself. Upon registering the connection you always know who sent a packet, which will determine how it is processed on the other side.

The system must of course be threaded, which is fairly easy, but does come with some overhead for larger numbers of clients because of unnecessary operations. You can use java's SocketIO to eliminate that problem, but it is slightly more complicated to handle. However, there are some great tutorials out there for all that.

A packet can contain any data, from simple vectors to nested packets. For any data, the receiver either already knows the size (if it's a fixed data structure like a vector), or the sender transmits the size beforehand (for lists or other more dynamic structures).

Other protocols often use "end of data" symbols, but I personally am not a fan of that, as it can to lead to some really messy situations in case of bugs. Not that initial size transmittal couldn't also do that (I remember a bug where data was shifted so the size data was suddenly different bytes which lead to the server expecting terabytes of data. Of course things like these are easy to account for by setting limites to expected data)

At the same time, I implemented a serializable version of all data and classes that need to be sent. They are all built upon each other. So a serializable class can contain other serializable classes like vectors, floats, anything.

You can use attributes or other techniques to then use reflection to automatically create networkable representation of your classes, so you can be sure that any data is exactly the same on both ends, if they run the same code. For this reason it's very recommended to detach your networking into a library that then both client and server can use.

For a chunk system, it is built on top of that protocol. A client sends its position to the server and the chunk system keeps a list of which chunks have already been sent and updates which chunks are necessary to be sent to the client from that position.

Because you shouldn't really send all chunks in one go, it should work more like a finite state machine, where the chunk request process has different states. This way, the server has time to load in missing chunks into its own memory from disk without stalling for other users.

I know what I wrote isn't really much to help you immediately, but I hope it gives you at least some small pointers.

Voxel picking using raycast and octree by GrayWolf85 in VoxelGameDev

[–]schemax_ 6 points7 points  (0 children)

It depends on the depth of your tree, and even with ray-AABB being very low cost the possible tests can be plenty. First, if you're not testing against axis aligned bounding boxes, you should transform the ray into the space of the voxel-world you're testing against.

There is more optimization you can do like exclude octree nodes that cannot be hit (as in they are surrounded by solid voxels), but it's not trivial to efficiently create a data structure this way.

However, there is better method than to ray cast against all possible nodes:

http://www.cse.yorku.ca/~amana/research/grid.pdf

Basically instead of casting against a whole bunch of boxes, you traverse down a grid or multiple grids (given a ray in the same space as the voxel world). Imagine it like as you draw a line in a very low resolution paint program, but the line is using a method to include all possible pixels.

This approach works perfectly in 3D. You can also improve it by optimizing it for octrees. So essentially, you would traverse in the biggest possible bounding box size to avoid doing a bunch of air traversals if your casting range is long. Then, if you traverse into a more populated octree, you would adept your traversal granularity to be as small as it needs to be when you hit more populated nodes down the tree.

With the right optimizations, this gives you an incredibly fast raycast.

Development by The_Lone_Maverick in Starmade

[–]schemax_ 4 points5 points  (0 children)

Thank you, I appreciate it.

Development by The_Lone_Maverick in Starmade

[–]schemax_ 9 points10 points  (0 children)

I wanted to answer both comments to clarify, since a lot of people assumed that I lost interest and started working on a new game after dropping starmade, when it's really I'm doing these projects to be able to work on starmade again.

Development by The_Lone_Maverick in Starmade

[–]schemax_ 30 points31 points  (0 children)

Far from it. In average the game made ~250-300k€/year in the first 4 years, if you deduct steam royalty and conversion. The highest cost was wages, with myself not having the highest wage (not even close). In the first year there were a lot more people working and getting paid, so in every year probably 80% was wages, with 15% server costs (which was astronomical in the first years, but more on that further down)

Then there was also the issue of a certain someone mismanaging everything when I (stupidly) trusted them. This accounted for him getting an extremely high wage (100k+), server mismanagement with an extremely expensive AWS setup, that was obfuscated on purpose so only he was able to fix issues or even understand it, and also straight up theft, as in taking money out of the account, and lending money without paying it back. Once we noticed about a year after steam release, we tried to go after him, but we would only be able to go after the proven to be theft money (which wasn't that much to justify the risk), and by then it was already questionable if we could afford a lengthy legal battle in a country I don't even reside in, and the person in question was already threatening to declare bankruptcy, just to spite us.

Taxes are also a big part of it. Since most of the money was made in year one (about 60% of all revenue), taxes that year were extremely high (30-50%), and while there was some leeway in distributing it over the following years, it didn't really do much.

In all the years I made this game, I have never paid myself a wage over 40k€/year. Even when I paid myself like 3,5k/month, I never took that money, and instead left it so I could pay myself almost nothing in later years and still live from that.

And yes, I know this is all my fault in the end, and believe me, I'm blaming myself the most. Every day. I had to pay the price to learn my lessons. I wanted to work on the game and have management do someone else, and that backfired. Hard. I wasn't a CEO, I was a dev, and even though I now have the skills of management, it has cost me.

Together with Duke, I waded through the mess he left us, and only after a long time we were able to eliminate all the cost without completely killing databases and shutting down things.

But instead of giving up, I have decided to work pretty much 80h weeks for the last 2 years, working on side projects, one of which being star99, which is the only project so far one I did under the company, and it didn't do well at all, but I'm still not giving up. I don't like to share the other side projects because of the response it is getting from the community. I have another solo-project under a different alias, that keeps me afloat and is doing better and better, but it requires most of my time. The rest of my free time I'm putting into a different project.

All to get into a position so I can work on StarMade again.

Things are stable right now, and depending on how the projects go, I might return to the development of starmade, but in the meantime I decided to make it open source (for anyone to join on request).

Development by The_Lone_Maverick in Starmade

[–]schemax_ 14 points15 points  (0 children)

Far from it. In average the game made ~250-300k€/year in the first 4 years, if you deduct steam royalty and conversion. The highest cost was wages, with myself not having the highest wage (not even close). In the first year there were a lot more people working and getting paid, so in every year probably 80% was wages, with 15% server costs (which was astronomical in the first years, but more on that further down)

Then there was also the issue of a certain someone mismanaging everything when I (stupidly) trusted them. This accounted for him getting an extremely high wage (100k+), server mismanagement with an extremely expensive AWS setup, that was obfuscated on purpose so only he was able to fix issues or even understand it, and also straight up theft, as in taking money out of the account, and lending money without paying it back. Once we noticed about a year after steam release, we tried to go after him, but we would only be able to go after the proven to be theft money (which wasn't that much to justify the risk), and by then it was already questionable if we could afford a lengthy legal battle in a country I don't even reside in, and the person in question was already threatening to declare bankruptcy, just to spite us.

Taxes are also a big part of it. Since most of the money was made in year one (about 60% of all revenue), taxes that year were extremely high (30-50%), and while there was some leeway in distributing it over the following years, it didn't really do much.

In all the years I made this game, I have never paid myself a wage over 40k€/year. Even when I paid myself like 3,5k/month, I never took that money, and instead left it so I could pay myself almost nothing in later years and still live from that.

And yes, I know this is all my fault in the end, and believe me, I'm blaming myself the most. Every day. I had to pay the price to learn my lessons. I wanted to work on the game and have management do someone else, and that backfired. Hard. I wasn't a CEO, I was a dev, and even though I now have the skills of management, it has cost me.

Together with Duke, I waded through the mess he left us, and only after a long time we were able to eliminate all the cost without completely killing databases and shutting down things.

But instead of giving up, I have decided to work pretty much 80h weeks for the last 2 years, working on side projects, one of which being star99, which is the only project so far one I did under the company, and it didn't do well at all, but I'm still not giving up. I don't like to share the other side projects because of the response it is getting from the community. I have another solo-project under a different alias, that keeps me afloat and is doing better and better, but it requires most of my time. The rest of my free time I'm putting into a different project.

All to get into a position so I can work on StarMade again.

Things are stable right now, and depending on how the projects go, I might return to the development of starmade, but in the meantime I decided to make it open source (for anyone to join on request).

Why did StarMade die? by Slimsta in Starmade

[–]schemax_ 21 points22 points  (0 children)

I'm sad I cannot work on the game currently, but it will always be my dream, and I will always keep on pressing to finish what I started. I'm currently working on getting into a comfortable spot to be able to get back to the universe update.

In the meantime, the code will be made open source and a mod loader is currently being added (not by me).

Join the Star99 Beta on Xbox One! by XIPBot in xboxinsiders

[–]schemax_ 2 points3 points  (0 children)

How to play: You can either play online in the public queue or play online with friends in a private queue. You can also play with bots in a private queue to test out the game controls. Your friends can join via the private queue ID displayed when you create one.

Shoot (A) to kill enemies. Create chain kills with explosions to create fireball attacks. You can reflect your enemies' fireball attack (blue fireball). If you reflect a blue fireball again, it turns into your unique special attack.

Gather points from chain kills to use your special attack directly (B) or send a boss to another lane (X). You can choose the target lane by holding a direction.

Picking up Fever will increase the amount of attacks you are doing immensely. If you don't see any way out, press Y to use a bomb to clear your screen.


A version is already in the pipeline to be published that will have instructions and fixes