Historically I've been reluctant to do this as people might be running
Optifine for performance rather than shaders, and the VBO renderer was
significantly slower when monitors were changing.
With the recent performance optimisations, the difference isn't as bad.
Given how many people ask/complain about the TBO renderer and shaders, I
think it's worth doing this, even if it's not as granular as I'd like.
Also changes how we do the monitor backend check. We now only check for
compatibility if BEST is selected - if there's an override, we assume
the user knows what they're doing (a bold assumption, if I may say so
myself).
- For TBOs, we now pass cursor position, colour and blink state as
variables to the shader, and use them to overlay the cursor texture
in the right place.
As we no longer need to render the cursor, we can skip the depth
buffer, meaning we have to do one fewer upload+draw cycle.
- For VBOs, we bake the cursor into the main VBO, and switch between
rendering n and n+1 quads. We still need the depth blocker, but can
save one upload+draw cycle when the cursor is visible.
This saves significant time on the TBO renderer - somewhere between 4
and 7ms/frame, which bumps us up from 35 to 47fps on my test world (480
full-sized monitors, changing every tick). [Taken on 1.18, but should be
similar on 1.16]
Like #455, this sets our uniforms via a UBO rather than having separate
ones for each value. There are a couple of small differences:
- Have a UBO for each monitor, rather than sharing one and rewriting it
every monitor. This means we only need to update the buffer when the
monitor changes.
- Use std140 rather than the default layout. This means we don't have
to care about location/stride in the buffer.
Also like #455, this doesn't actually seem to result in any performance
improvements for me. However, it does make it a bit easier to handle a
large number of uniforms.
Also cleans up the generation of the main monitor texture buffer:
- Move buffer generation into a separate method - just ensures that it
shows up separately in profilers.
- Explicitly pass the position when setting bytes, rather than
incrementing the internal one. This saves some memory reads/writes (I
thought Java optimised them out, evidently not!). Saves a few fps
when updating.
- Use DSA when possible. Unclear if it helps at all, but nice to do :).
This takes a non-trivial amount of time on the render thread[^1], so
worth doing.
I don't actually think the allocation is the heavy thing here -
VisualVM says it's toWorldPos being slow. I'm not sure why - possibly
just all the block property lookups? [^2]
[^1]: To be clear, this is with 120 monitors and no other block entities
with custom renderers. so not really representative.
[^2]: I wish I could provide a narrower range, but it varies so much
between me restarting the game. Makes it impossible to benchmark
anything!
The VBO renderer needs to generate a buffer with two quads for each
cell, and then transfer it to the GPU. For large monitors, generating
this buffer can get quite slow. Most of the issues come from
IVertexBuilder (VertexConsumer under MojMap) having a lot of overhead.
By emitting a ByteBuffer directly (and doing so with Unsafe to avoid
bounds checks), we can improve performance 10 fold, going from
3fps/300ms for 120 monitors to 111fps/9ms.
See 41fa95bce4 and #1065 for some more
context and other exploratory work. The key thing to note is we _need_ a
separate version of FWFR for emitting to a ByteBuffer, as introducing
polymorphism to it comes with a significant performance hit.
- Move all RenderType instances into a common class.
Cherry-picked from 41fa95bce4:
- Render GL_QUADS instead of GL_TRIANGLES.
- Remove any "immediate mode" methods from FWFR. Most use-cases can be
replaced with the global MultiBufferSource and a proper RenderType
(which we weren't using correctly before!).
Only the GUI code (WidgetTerminal) needs to use the immediate mode.
- Pre-convert palette colours to bytes, storing both the coloured and
greyscale versions as a byte array.
Cherry-picked from 3eb601e554:
- Pass lightmap variables around the various renderers. Fixes#919 for
1.16!
"Instead, it is a standard program, which its API into the programs that it launches."
becomes
"Instead, it is a standard program, which injects its API into the programs that it launches."
A little shorter and more explicit than constructing the Vector3d
manually. Fixes an issue where sounds were centered on the bottom left
of speakers, not the middle (see cc-tweaked/cc-restitched#85).
See #1061, closes#1064.
Nobody ever seems to implement this correctly (though it's better than
1.12, at least we've not seen any crashes), and this isn't a fight I
care enough about fighting any more.
There's a couple of alternative ways to solve this. Ideally we'd send
our network messages at the same time as MC does
(ChunkManager.playerLoadedChunk), but this'd require a mixin.
Instead we just rely on the fact that if the chunk isn't loaded,
monitors won't have done anything and so we don't need to send their
contents!
Fixes#1047, probably doesn't cause any regressions. I've not seen any
issues on 1.16, but I also hadn't before so ¯\_(ツ)_/¯.
This was added in the 1.13 update and I'm still not sure why. Other mods
seem to get away without it, so I think it's fine to remove.
Also remove the fake net manager, as that's part of Forge nowadays.
Fixes#1044.
- Fixes#1026
- The remaining bytes counter wasn't being decremented, so the code that
splits off smaller packets was unreachable. Thus all file slices were
being put into a single UploadFileMessage packet.
- Fix UpgradeSpeakerPeripheral not calling super.detach (so old
computers were never cleaned up)
- Correctly lock computer accesses inside SpeakerPeripheral
Fixes#1003.
Fingers crossed this is the last bug. Then I can bump the year and push
a new release tomorrow.
We're still a few days away from release, but don't think anything else
is going to change. And I /really/ don't want to have to write this
changelog (and then merge into later versions) on the 25th.
While Minecraft will automatically push a new buffer when one is
exhausted, this doesn't help if there's only a single buffer in the
queue, and you end up with stutter.
By enquing a buffer when receiving sound we ensure there's always
something queued. I'm not 100% happy with this solution, but it does
alleviate some of the concerns in #993.
Also reduce the size of the client buffer to 0.5s from 1.5s. This is
still enough to ensure seamless audio when the server is running slow (I
tested at 13 tps, but should be able to go much worse).
When the game is paused in SSP world, speakers are not ticked. However,
System.nanoTime() continues to increase, which means the next tick
speakers believe there has been a big jump and so schedule a bunch of
extra audio.
To avoid this, we keep track of how long the game has been paused offset
nanoTime by that amount.
Fixes#994
It's just more confusing having to keep track of where the ByteBuffer is
at. In this case, I think we were forgetting to rewind after computing
the digest.
Hopefully we'll be able to drop some of these in 1.17 as Java 16 has
a few more ByteBuffer methods
Fixes#992
Speakers can now play arbitrary PCM audio, sampled at 48kHz and with a
resolution of 8 bits. Programs can build up buffers of audio locally,
play it using `speaker.playAudio`, where it is encoded to DFPWM, sent
across the network, decoded, and played on the client.
`speaker.playAudio` may return false when a chunk of audio has been
submitted but not yet sent to the client. In this case, the program
should wait for a speaker_audio_empty event and try again, repeating
until it works.
While the API is a little odd, this gives us fantastic flexibility (we
can play arbitrary streams of audio) while still being resilient in the
presence of server lag (either TPS or on the computer thread).
Some other notes:
- There is a significant buffer on both the client and server, which
means that sound take several seconds to finish after playing has
started. One can force it to be stopped playing with the new
`speaker.stop` call.
- This also adds a `cc.audio.dfpwm` module, which allows encoding and
decoding DFPWM1a audio files.
- I spent so long writing the documentation for this. Who knows if it'll
be helpful!
- Remove all the hungrarian notation in variables. Currently leaving
the format of rednet messages for now, while I work out whether this
counts as part of the public API or not.
- Fix the "repeat" program failing with broadcast packets. This was
introduced in #900, but I don't think anybody noticed. Will be more
relevant when #955 is implemented though.
This means that if the current player is breaking a cable/wired modem,
only the part they're looking at has breaking progress. Closes#355.
A mixin is definitely not the cleanest way to do this. There's a couple
of alternatives:
- CodeChickenLib's approach of overriding the BlockRendererDispatcher
instance with a delegating subclasss. One mod doing this is fine,
several is Not Great.o
- Adding a PR to Forge: I started this, and it's definitely the ideal
solution, but any event for this would have a ton of fields and just
ended up looking super ugly.
I assume people have broken coroutine dispatchers - I didn't think it
was possible to queue an actual event with no type.
See cc-tweaked/cc-restitched#31. Will fix it too once merged downstream!
Opening a screen KeyBinding.releaseAll(), which forces all inputs to be
considered released. However, our init() function then calls
grabMouse(), which calls Keybinding.setAll(), undoing this work.
The fix we're going for here is to call releaseAll() one more time[^1]
after grabbing the mouse. I think if this becomes any more of a problem,
we should roll our own grabMouse which _doesn't_ implement any specific
behaviour.
Fixes#975
[^1]: Obvious problem here is that we do minecraft.screen=xyz rather
than setScreen. We need to - otherwise we'd just hit a stack
overflow - but it's not great.
Peripherals can now have multiple types:
- A single primary type. This is the same as the current idea of a
type - some identifier which (mostly) uniquely identifies this kind
of peripheral. For instance, "speaker" or "minecraft:chest".
- 0 or more "additional" types. These are more like traits, and
describe what other behaviour the peripheral has - is it an
inventory? Does it supply additional peripherals (like a wired
modem)?.
This is mostly intended for the generic peripheral system, but it might
prove useful elsewhere too - we'll have to see!
- peripheral.getType (and modem.getTypeRemote) now returns 1 or more
values, rather than exactly one.
- Add a new peripheral.hasType (and modem.hasTypeRemote) function which
determines if a peripheral has the given type (primary or
additional).
- Change peripheral.find and all internal peripheral methods to use
peripheral.hasType instead.
- Update the peripherals program to show all types
This effectively allows you to do things like
`peripheral.find("inventory")` to find all inventories.
This also rewrites the introduction to the peripheral API, hopefully
making it a little more useful.
- Capability invalidation and tile/block entity changes set a dirty bit
instead of refetching the peripheral immediately.
- Then on the block's tick we recompute the peripheral if the dirty bit
is set.
Fixes#696 and probably fixes#882. Some way towards #893, but not
everything yet.
This is probably going to break things horribly. Let's find out!
- Bump copy-cat version to have support for initial files in
directories and the blit fixes.
- Add an example nft image and move example nfp into a data/ directory.
- Fix nft parser not resetting colours on the start of each line.
- Subscribe to the "on add reload listener" event, otherwise we don't
get reloads beyond the first one! This means we no longer need to
cast the resource manager to a reloadable one.
- Change the mount cache so it's keyed on path, rather than "path ✕
manager".
- Update the reload listener just to use the mount cache, rather than
having its own separate list. I really don't understand what I was
thinking before.
- Some improvements to validation of monitors. This rejects monitors
with invalid dimensions, specifically those with a width or height
of 0. Should fix#922.
- Simplify monitor collapsing a little. This now just attempts to
resize the four "corner" monitors (where present) and then expands
them if needed. Fixes#913.
- Rewrite monitor expansion so that it's no longer recursive. Instead
we track the "origin" monitor and replace it whenever we resize to
the left or upwards.
Also add a upper bound on the loop count, which should prevent things
like #922 happening again. Though as mentioned above, validation
should prevent this anyway.
- Some small bits of cleanup to general monitor code.
I have absolutely no confidence that this code is any better behaved
than the previous version. Let's find out I guess!
- Add a new GenericPeripheral interface. We don't strictly speaking
need this - could put this on GenericSource - but the separation
seems cleaner.
- GenericPeripheral.getType() returns a new PeripheralType class, which
can either be untyped() or specify a type name. This is a little
over-engineered (could just be a nullable string), but I'm planning
to allow multiple types in the future, so want some level of
future-proofing.
- Thread this PeripheralType through the method gathering code and
expose it to the GenericPeripheralProvider, which then chooses an
appropriate name.
This is a little ugly (we're leaking information about peripherals
everywhere), but I think is fine for now. It's all private internals
after all!
Closes#830
- Move TaskCallback into the API and make it package private. This
effectively means it's not an API class, just exists there for
convenience reasons.
- Replace any usage of TaskCallback.make with
ILuaContext.executeMainThreadTask.
- Some minor formatting/checkstyle changes to bring us inline with
IntelliJ config.
- Allow any tool to break an "instabreak" block (saplings, plants,
TNT). Oddly this doesn't include bamboo or bamboo sapings (they're
marked as instabreak, only to have their strength overridden again!),
so we also provide a tag for additional blocks to allow.
- Hoes and shovels now allow breaking any block for which this tool is
effective.
- Use block tags to drive any other block breaking capabilities. For
instance, hoes can break pumpkins and cactuses despite not being
effective.
This should get a little nicer in 1.17, as we can just use block tags
for everything.
Let's see how this goes.
- Update references to the new repo
- Use rrsync on the server, meaning make-doc.sh uploads relative to the
website root.
- Bump Gradle wrapper to 7.2. Not related to this change, but possibly
fixes running under Java 16. Possibly.
Yes, I know this is a terrible feature. But it's been a long week and
I'm so tired.
Also fix the ordering in motd_spec. Who thought putting the month first
was reasonable?
This means wired peripherals now correctly track their current mounts
and attached state, rather than inheriting from the origin wired modem.
Closes#890
Allows us to run multiple "computers" in parallel and send messages
betwene them. I don't think this counts as another test framework, but
it's sure silly.
- Fix broken /cctest marker
- Correctly wait for the screenshot to be taken before continuing.
- Filter out client tests in a different place, meaning we can remove
the /cctest runall command
- Bump kotlin version