0 Members and 1 Guest are viewing this topic.
You may have seen a couple of screenshots of this appear on IRC, at the time of writing it looks like this:They're pulse circuits, so it looks like a bunch of things are incorrect but that's just because of their delay.
Anyway, the goal as I set it for this project is to be able to build/test/run redstone circuits without various minecraft annoyances, most of which can be fixed with mods I suppose..
Basically it's creative mode on steroids. Nothing that distracts from just building circuits. World-edit-like godmode editing. And I have some plans for putting in things like displaying delays and critical paths and some automated circuit testing stuff (such as cycling through a bunch of different inputs without having to build a circuit to do it). None of that exists just yet, I'm just doing the basics now. Also, the ability to pauze, step, fast-forward redstone simulation.
Some redstone logic already works to some degree, for example: - torches, both floor-mounted and wall-mounted. Don't burn out though, and I'm not sure whether to make them burn out. They also react to 1 tick pulses, which is wrong. (that's how the above screenshot has 1 tick pulses)
- repeaters. You may have hear me complain about them. A normal 1-tick repeater that isn't locked works fine. Other delays may or may not do what they're supposed to do, the screenshot above is testing how they respond to 1 tick pulses and they respond correctly. I'm not sure about other inputs though. Also, locks make no sense and are currently incorrect (correct behaviour requires time travel).
- redstone dust, I think, works correctly in terms of which blocks it powers, what it looks like (apart from the particle effect), how far signals travel, and signals don't go down transparent diodes.
Some things are not there but will be there soon: - comparators - editing (it just loads and simulates now)Some things may or may not ever be included: - pistons (I know you like them, but they suck to simulate, and I'm sure you remember how long they caused trouble in MC)
- shadows / lightlevels would be pretty, but not useful and would slow down rendering, particularly of complex+big maps.Trickery usedThe world can get pretty big (256x256x256 at least, it should work with 1024x1024x512 as well but not tested), which is smaller than "real minecraft", but still brings some challenges.For example, it's impossible in general to reupload all geometry every frame, or you'd have maybe 1 frame per second. In order to avoid having to reupload too much stuff that wasn't changed, the world is divided in 16x16x16 chunk. Chunks with no changes are left alone.
However, naively, if a redstone signal changes, that means a change in a chunk because you'd have to update some texture coordinates and that means reuploading the geometry, this time with different texture coordinates. That would make far too many chunks be reuploaded, so to counter that, I've decoupled powerlevels from geometry
, so I can update them separately with only a tiny upload of only 2kb (16x16x16/2 because power levels can be packed in nibbles) versus about 1kb per solid block (minus faces that touch other solid blocks) in the chunk. It's a bad deal only if there are 1 or 2 blocks in a chunk, which is not the common case.The powerlevel data is also used by "objects" (torches, repeaters, etc) to determine their state, even for the lock-bar of repeaters, so as long as only redstone signals change, no geometry is reuploaded.To avoid having to deal with "ordering" with transparent parts (torches draw some transparent parts), transparent pixels are discarded. AA tends not to like that, but it works in combination with sample shading.Possible future trickery: if I can figure out how to do it well, maybe fuse some faces and use texture wrapping. That would significantly reduce the polycount in some cases, but I'd have to careful not to mess anything up.
Polycount hasn't really been a problem so far though, a million randomly placed (but not multiple at the same location) solid blocks still render at 30FPS (on a HD6950, +vsync), I doubt any real build would even come close to that.
Tech used/platformC# and OpenGL 4. The biggest compatibility obstacle is probably the extensions I used and buggy/old GPU drivers.
Redstone (and repeaters) on walls, ceilings, torches on ceilings as well? That'd be very useful
A nice feature would be to save "patterns" like gatters or special configurations and the ability to place them down wherever you like and in every orientation.
QuoteSome redstone logic already works to some degree, for example: - torches, both floor-mounted and wall-mounted. Don't burn out though, and I'm not sure whether to make them burn out. They also react to 1 tick pulses, which is wrong. (that's how the above screenshot has 1 tick pulses)Why is this wrong?
"time travel"? Weird data dependancies? Or have I forgotten how they work? AFAIK it's only that the repeater doesn't change state if it's powered from the side.
How did you implement this [redstone dust]? Minecraft does it exactly how I do it in crafti: Connected redstone dust is treated like a single thing and updated at once (for timing and loop-avoiding purposes)
If you have chunks (exactly like minecraft) anyway, why not make the map infinite?
QuoteHowever, naively, if a redstone signal changes, that means a change in a chunk because you'd have to update some texture coordinates and that means reuploading the geometry, this time with different texture coordinates. That would make far too many chunks be reuploaded, so to counter that, I've decoupled powerlevels from geometryPowerlevels don't have to be sent to the GPU. If you mean the color of the redstone wire/dust, that's IMHO unnecessary complexity. GPUs and DMA are fast enough, so if you use VBOs, everything should be fine without these optimizations. Did you do any performance tests?
QuoteQuoteSome redstone logic already works to some degree, for example: - torches, both floor-mounted and wall-mounted. Don't burn out though, and I'm not sure whether to make them burn out. They also react to 1 tick pulses, which is wrong. (that's how the above screenshot has 1 tick pulses)Why is this wrong?Uhm, I guess it isn't. I'm not sure how that's supposed to work tbh. Aren't torches supposed to ignore 1-tick pulses? Why else are "1 tick torch transmission" things so "special"? Then again, that circuit was always a 1 tick clock IIRC.
Quote"time travel"? Weird data dependancies? Or have I forgotten how they work? AFAIK it's only that the repeater doesn't change state if it's powered from the side.Yea normally it's simple, but for example if you power a repeater at the same time you power the lock, it gets locked in OFF state, even though at that point it is not powered from the side yet.It gets worse if you add an other repeater that simultaneously tries to lock the lock. Please tell me you know how that works..
QuoteHow did you implement this [redstone dust]? Minecraft does it exactly how I do it in crafti: Connected redstone dust is treated like a single thing and updated at once (for timing and loop-avoiding purposes)Basically I floodfill through it starting from active power supplies.
QuoteIf you have chunks (exactly like minecraft) anyway, why not make the map infinite?Well right now, I'd run out of coordinate space. I could use a wider type there I guess. Also because of the way I did it, I'd run out of floating point resolution relatively quickly if you go much further from the origin than you can now, I'd have to throw in some more trickery to avoid that. Might happen.
QuoteOh it was fine .. on a small enough or sparse enough map. If 1 million cubes is small to you, this will never be good enough. 1 million cubes is right up there with the PCIe 2.0 x16 throughput limit of 0.8GB per update (assuming 10Hz), actually slightly beyond the limit. Of course that case would only be hit if all chunks changed and they were all in the frustum, but that's not something that's completely impossible. Now this will not be a problem again (unless I put in pistons).
Oh it was fine .. on a small enough or sparse enough map. If 1 million cubes is small to you, this will never be good enough. 1 million cubes is right up there with the PCIe 2.0 x16 throughput limit of 0.8GB per update (assuming 10Hz), actually slightly beyond the limit. Of course that case would only be hit if all chunks changed and they were all in the frustum, but that's not something that's completely impossible. Now this will not be a problem again (unless I put in pistons).
The weird thing with those is, that if you "tick" every block in a chunk in the same order (0/0/0),(0/0/1),...,(0/1/0),...(15/15/15). you can see "invalid" states.As calculation doesn't happen parallel to rendering (that'd be horrible, both usability- and code-wise), (15/15/15) can react to a change of (15/15/14) in the same tick. Minecraft does it a bit differently: Only a few blocks of each chunk are "tick"ed each frame. They're chosen randomly, so you get such states very seldom. It can cause horrible bugs, though.. I also thought about a game-of-life like implementation, like double-buffering. Copy the redstone state of the chunk before doing ticks and only after every block recalculated itself, make the new state the current one.
I get 1000000 (cubes) * 6 (faces) * 4 (vertices) * 5 (x/y/z/u/v) * 4 (bytes in a float) ~= 500 MiB and that's EVERYTHING. In the ultimate WORST case.
This looks interesting. Do you also plan on creating a .scematic exporter so that you can paste anything you make in a real minecraft world?
Quote from: Vogtinator on August 23, 2014, 03:06:21 pmThe weird thing with those is, that if you "tick" every block in a chunk in the same order (0/0/0),(0/0/1),...,(0/1/0),...(15/15/15). you can see "invalid" states.As calculation doesn't happen parallel to rendering (that'd be horrible, both usability- and code-wise), (15/15/15) can react to a change of (15/15/14) in the same tick. Minecraft does it a bit differently: Only a few blocks of each chunk are "tick"ed each frame. They're chosen randomly, so you get such states very seldom. It can cause horrible bugs, though.. I also thought about a game-of-life like implementation, like double-buffering. Copy the redstone state of the chunk before doing ticks and only after every block recalculated itself, make the new state the current one.I'm using the "fill a new buffer, then make it the current one" approach now. I'm not sure how the repeater locking enigma interacts with this. I still don't see how this makes sense though:Especially not since that appears to happen consistently.But then you add an other repeater, and suddenly:
QuoteI get 1000000 (cubes) * 6 (faces) * 4 (vertices) * 5 (x/y/z/u/v) * 4 (bytes in a float) ~= 500 MiB and that's EVERYTHING. In the ultimate WORST case.I put a bit more in there (normal, texture array index, stuff to paint redstone dust directly onto it, which might be a bit wasteful perhaps), comes out at 48 bytes per vertex, just over 1GB for a million cubes. But that's all just a factor of 2 anyway, make it 2 million cubes and you have the same problem again.
Debugging this should be easy. Do a breakpoint at the repeater's tick function, in the block to lock it and look at the redstone state of the inputs.I don't see any differences of the two pictures though. (Uh, this sentence sounds and looks weird. Where's my mistake?)
A BIT wasteful? That's a massive understatement.. The normal is unnecessary (the GPU calculates it faster in a shader every frame), as is the redstone dust stuff. I would also replace the texture array index by something stateful. I don't know whether glBindTexture(id, GL_TEXTURE_2D) still exists.
Quote from: Vogtinator on August 23, 2014, 04:43:55 pmDebugging this should be easy. Do a breakpoint at the repeater's tick function, in the block to lock it and look at the redstone state of the inputs.I don't see any differences of the two pictures though. (Uh, this sentence sounds and looks weird. Where's my mistake?)How do I debug minecraft? To clarify, those pictures are of how it should be, not of how it currently is in my clone.
QuoteA BIT wasteful? That's a massive understatement.. The normal is unnecessary (the GPU calculates it faster in a shader every frame), as is the redstone dust stuff. I would also replace the texture array index by something stateful. I don't know whether glBindTexture(id, GL_TEXTURE_2D) still exists.I'd have to add a geometry shader stage for the normals. And do some pretty wonky stuff in it. It's possible, but not worth it especially since the reason would be to make things worse. After all, this isn't about turning 1GB into 500MB, it's about turning 8MB or so into 500MB, that doesn't make any sense. The biggest problem would remain anyway: it just plain takes too much to generate all that geometry data. It would still do so without normals and crap.And statefulness would break my nice 3-calls-per-chunk renderer.
Oh, I thought it was your implementation... The reason could be that minecraft does it the way I mentioned: Random ticks per chunk, but it has to tick every block in a chunk first before it ticks a block the second time (I'm not sure how to explain it better). What happens if you connect two not gates to the repeater inputs (input & lock) instead of a repeater? Does the behaviour change if you change orientation, location etc.?
With statefulness my old Minecraft clone (years ago, lwjgl) achieved a 2-calls-per-chunk renderer (IIRC. It was an experiment how to get most performance out of LWJGL with a lot of cubes and big worlds)
Quote from: Vogtinator on August 23, 2014, 05:09:40 pmOh, I thought it was your implementation... The reason could be that minecraft does it the way I mentioned: Random ticks per chunk, but it has to tick every block in a chunk first before it ticks a block the second time (I'm not sure how to explain it better). What happens if you connect two not gates to the repeater inputs (input & lock) instead of a repeater? Does the behaviour change if you change orientation, location etc.?Could you draw the circuit?
A repeater is itself a block, so it adds a delay of 1 tick minimum.