docs: @SubscribeEvent
      public void postRender(RenderWorldLastEvent event)
      {
          // Check that the video producer and frame type match - eg if this is a colourmap frame, then
          // only the colourmap videoproducer needs to do anything.
          boolean colourmapFrame = TextureHelper.colourmapFrame;
          boolean colourmapVideoProducer = this.videoProducer.getVideoType() == VideoType.COLOUR_MAP;
          if (colourmapFrame != colourmapVideoProducer)
              return;
  
          EntityPlayerSP player = Minecraft.getMinecraft().player;
          float x = (float) (player.lastTickPosX + (player.posX - player.lastTickPosX) * event.getPartialTicks());
          float y = (float) (player.lastTickPosY + (player.posY - player.lastTickPosY) * event.getPartialTicks());
          float z = (float) (player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * event.getPartialTicks());
          float yaw = player.prevRotationYaw + (player.rotationYaw - player.prevRotationYaw) * event.getPartialTicks();
          float pitch = player.prevRotationPitch + (player.rotationPitch - player.prevRotationPitch) * event.getPartialTicks();
  
          long time_before_ns = System.nanoTime();
  
          if (observer != null)
              observer.frameProduced();
  
          if (time_before_ns < retry_time_ns)
              return;
  
          boolean success = false;
  
          long time_after_render_ns;
  
          try
          {
              int size = this.videoProducer.getRequiredBufferSize();
  
              if (AddressHelper.getMissionControlPort() == 0) {
                  success = true;
  
                  if (envServer != null) {
                      // Write the obs data into a newly allocated buffer:
                      byte[] data = new byte[size];
                      this.buffer.clear();
                      this.videoProducer.getFrame(this.missionInit, this.buffer);
                      this.buffer.get(data); // Avoiding copy not simple as data is kept & written to a stream later.
                      time_after_render_ns = System.nanoTime();
  
                      envServer.addFrame(data);
                  } else {
                      time_after_render_ns = System.nanoTime();
                  }
              } else {
                  // Get buffer ready for writing to:
                  this.buffer.clear();
                  this.headerbuffer.clear();
                  // Write the pos data:
                  this.headerbuffer.putFloat(x);
                  this.headerbuffer.putFloat(y);
                  this.headerbuffer.putFloat(z);
                  this.headerbuffer.putFloat(yaw);
                  this.headerbuffer.putFloat(pitch);
                  // Write the frame data:
                  this.videoProducer.getFrame(this.missionInit, this.buffer);
                  // The buffer gets flipped by getFrame(), but we need to flip our header buffer ourselves:
                  this.headerbuffer.flip();
                  ByteBuffer[] buffers = {this.headerbuffer, this.buffer};
                  time_after_render_ns = System.nanoTime();
  
                  success = this.connection.sendTCPBytes(buffers, size + POS_HEADER_SIZE);
              }
  
              long time_after_ns = System.nanoTime();
              float ms_send = (time_after_ns - time_after_render_ns) / 1000000.0f;
              float ms_render = (time_after_render_ns - time_before_ns) / 1000000.0f;
              if (success)
              {
                  this.failedTCPSendCount = 0;    // Reset count of failed sends.
                  this.timeOfLastFrame = System.currentTimeMillis();
                  if (this.timeOfFirstFrame == 0)
                  	this.timeOfFirstFrame = this.timeOfLastFrame;
                  this.framesSent++;
  	            //            System.out.format("Total: %.2fms; collecting took %.2fms; sending %d bytes took %.2fms\n", ms_send + ms_render, ms_render, size, ms_send);
  	            //            System.out.println("Collect: " + ms_render + "; Send: " + ms_send);
              }
          }
          catch (Exception e)
          {
              System.out.format(e.getMessage());
          }
          
          if (!success) {
              System.out.format("Failed to send frame - will retry in %d seconds\n", RETRY_GAP_NS / 1000000000L);
              retry_time_ns = time_before_ns + RETRY_GAP_NS;
              this.failedTCPSendCount++;
          }
      }