Jump to content

[SOLVED] [1.8] Reducing Network Traffic


EverythingGames
 Share

Recommended Posts

I am currently using the client tick event to check mouse input so I can call a method every tick on both sides (so I can play sounds, spawn entities, manipulate ItemStack NBT, etc.). Yes, I absolutely need to call this method every tick - some items held will have a built-in delay for calling the method. Right now, I am sending a packet to the server in the client tick event, based on mouse input, to call the method and to also send the same packet to the client (Bi-Directional packet) to also call the method. This works well, it calls the method on both sides, however sending packets at that rate and size is a pretty bad idea. It was recommended that I send the packet once setting a Boolean to true, and to save the Boolean in IEEP.

 

Would it be best to send the packet once in the client tick event and then check the IEEP Boolean on the player tick event? Is the player tick event called on both sides? What is the best way of reducing this network traffic while still being able to achieve the same results? Any input is greatly appreciated, thanks.

Development of Plugins [2012 - 2014] Development of Mods [2012 - Current]

Link to comment
Share on other sites

It was recommended that I send the packet once setting a Boolean to true, and to save the Boolean in IEEP.

 

Would it be best to send the packet once in the client tick event and then check the IEEP Boolean on the player tick event? Is the player tick event called on both sides? What is the best way of reducing this network traffic while still being able to achieve the same results? Any input is greatly appreciated, thanks.

 

1. Yes, if you need to know exacly when player is holding down button/mouse the best way is to send packet containing key(int) and pressed(boolean).

- ClientTickEvent is called once on client per tick, so using it would be "fine", but not entirely, because you would also have to know (on client) if previous-tick button/mouse state is different (and if so - send state-changed packet), which requires additional fields (check is needed so you don't send packet with button state every tick).

- What you can utilize are input events, but I am not sure they work in all cases (might have to use ClientTick after all).

- If you would have to do that - simply hold list of previous states and send apcket only if you know state is different than one from prev-tick.

2. Yes, PlayerTickEvent is called for both sides for each EntityPlayer (mening on client it will be called for every loaded-by-client player). It is also (like other TickEvents) called twice with Phase.

3. Pretty much point 1.

1.7.10 is no longer supported by forge, you are on your own.

Link to comment
Share on other sites

Packet code?

Pretty much irrelevant to the question - I am not learning how to read and write data from packets.

- I am reading and writing an int (Mouse button pressed) and an ItemStack.

 

It was recommended that I send the packet once setting a Boolean to true, and to save the Boolean in IEEP.

 

Would it be best to send the packet once in the client tick event and then check the IEEP Boolean on the player tick event? Is the player tick event called on both sides? What is the best way of reducing this network traffic while still being able to achieve the same results? Any input is greatly appreciated, thanks.

 

1. Yes, if you need to know exacly when player is holding down button/mouse the best way is to send packet containing key(int) and pressed(boolean).

- ClientTickEvent is called once on client per tick, so using it would be "fine", but not entirely, because you would also have to know (on client) if previous-tick button/mouse state is different (and if so - send state-changed packet), which requires additional fields (check is needed so you don't send packet with button state every tick).

- What you can utilize are input events, but I am not sure they work in all cases (might have to use ClientTick after all).

- If you would have to do that - simply hold list of previous states and send apcket only if you know state is different than one from prev-tick.

2. Yes, PlayerTickEvent is called for both sides for each EntityPlayer (mening on client it will be called for every loaded-by-client player). It is also (like other TickEvents) called twice with Phase.

3. Pretty much point 1.

Yeah, I was thinking along the same lines. I would like to be able to use the MouseEvent so that I would not need an additional check for the Mouse button being down and not down. Though, I see no way of actually checking is Mouse Button X is not down. Really what I need here is - if Mouse pressed Boolean=true, else if Mouse is not pressed Boolean = false. Send packet once each time to set Boolean to true / false. While Boolean is true, call code on both sides, else return.

 

I'll get to work on it straight away and will post with further progress / questions.

Development of Plugins [2012 - 2014] Development of Mods [2012 - Current]

Link to comment
Share on other sites

There's not really anything wrong with sending a packet each tick if that's really what your code requires - Minecraft sends dozens if not hundreds of packets each tick.

 

However, I don't see why you would need to send the same packet back to the client; can't you just run the code directly from the client side before or after you send the packet to the server, or are you relying on something happening on the server that gets sent in the response?

 

As a comparison, most Minecraft code that sends a packet to the server just sends it one way and runs the code directly on the client, e.g. when a player left-clicks an entity, the attack/action packet is sent to the server, and the client immediately starts processing the player's left click action without waiting for any further data. This is all under the expectation that client-side code is mostly irrelevant except for animations, particles, and the like, so any 'effects' such as damage mean nothing unless on the server.

 

TLDR; cut your packet numbers in half by eliminating the packet from server -> client.

Link to comment
Share on other sites

There's not really anything wrong with sending a packet each tick if that's really what your code requires - Minecraft sends dozens if not hundreds of packets each tick.

 

However, I don't see why you would need to send the same packet back to the client; can't you just run the code directly from the client side before or after you send the packet to the server, or are you relying on something happening on the server that gets sent in the response?

 

As a comparison, most Minecraft code that sends a packet to the server just sends it one way and runs the code directly on the client, e.g. when a player left-clicks an entity, the attack/action packet is sent to the server, and the client immediately starts processing the player's left click action without waiting for any further data. This is all under the expectation that client-side code is mostly irrelevant except for animations, particles, and the like, so any 'effects' such as damage mean nothing unless on the server.

 

TLDR; cut your packet numbers in half by eliminating the packet from server -> client.

 

That makes more sense. My code does require that a packet is sent every tick (or every X amount of ticks depending on the item's delay). The reason that I did not just call the code in the ClientTickEvent and then sending the packet to execute on the server side was because of pure aesthetics in the code itself - I handled everything in one packet and kind of kept key / mouse input separate from everything excluding networking, which is foolish now that you mention that it would cut the packets in half...that will change. Minimizing networking traffic seems great and efficient, though sending a packet each tick, or every X amount of ticks, would cut down on implementing IEEP - saving time.

 

For anyone who would want to not send a packet each tick, here is a bit on (untested) code that will allow you to do that:

@SubscribeEvent
public void onEvent(ClientTickEvent event)
{
	boolean pressed = Mouse.isButtonDown(0);
	boolean packetSent = false;
	if(!event.phase.equals(Phase.START)) return;
	if(pressed && !packetSent)
	{
		//Send packet to change boolean to true
		packetSent = true;
	}
	if(!pressed && packetSent)
	{
		//Send packet to change boolean to false
		packetSent = false;
	}
}

 

EDIT: Above code needs a minor fixing - the concept works but the reset (setting the Boolean back to false is broken). I'm sure someone can figure something out and use it.

 

One last question - if I need the code called on both sides while the player is actively in the world, and this check applies for any players with my item, why can't I just call the code in the PlayerTickEvent and check the Mouse button there and not have to send packets at all?

Development of Plugins [2012 - 2014] Development of Mods [2012 - Current]

Link to comment
Share on other sites

Because the server side has no concept of the Mouse or what state it is in.

 

For the 'packetSent' variable, I might prefer to call it 'mouseClicked' or something, since it is tracking when the state of the mouse changes, but that's just a matter of how you look at it (not a big deal, obviously). Also, it would be wise to have the same logic on the server, so each time the packet is sent with the current mouse state, the server can validate it before processing anything else, this way if somehow the packet gets sent a bunch of times in a row with 'mouseClicked = true', it doesn't result in extra actions.

 

As for clean code - that's a good thing to strive for, and if you look again at vanilla, you'll notice that, in the example I gave earlier, the packet simply calls the same code that the client called, namely EntityPlayer#attackTargetEntityWithCurrentItem, with some extra validation server side, of course. This way all of the logic is contained in that one method, and either side can call it as need be, so there is no code duplication.

Link to comment
Share on other sites

I actually ended up writing listeners that you implement. Pretty much like an event (considering the Listener you implement event handles for you), except unlike an event, you extend the specific Listener class and it gives you a few methods (depending on the listener type) that you must override. For example, I have a ListenerClientMouse class extending ListenerClient (which ultimately extends Listener, except ListenerClient is client side only, obviously). The ListenerClientMouse listens for when the user is holding down the mouse, when the mouse is not being held down (not doing anything), when the mouse was clicked (semi-automatic mouse click), and finally when the mouse was released (semi-automatic mouse released).

 

Using the 'MouseListener' that I wrote, I can now easily send a packet to the server once per click (regardless if user is holding, the method is called only once meaning only one packet is sent), and once per release (again, only called one, only one packet sent). A boolean is set upon click / release in IEEP and checked on the PlayerTickEvent. Everything worked like a charm, though it seemed like too much effort for a bit of optimization. The code is similar to the code shown above.

Development of Plugins [2012 - 2014] Development of Mods [2012 - Current]

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Hello I'm working on playing mods with friends but forge is giving me the exit code 1. I have tried using the curseforge to run it but same outcome. I've uninstalled minecraft and java. I looked online for any solutions and I've tried different versions of 1.19.2, nothing made a difference. There are currently no mods just forge. Log: https://gist.github.com/ExpiredPoptarts/19d7ff941fc62c9dc0b3b87ef3f65dc8
    • Custom lamp problem 1.12.2 is a problem that can occur when using the custom lamps mod in version 1.12.2 of Minecraft. The issue is caused when two or more custom lamps are placed in close proximity to each other, causing them to conflict with each other and malfunction. This can result in a variety of issues such as the lamps not lighting up, flickering, or not responding to game commands. The problem can be resolved by ensuring that custom lamps are placed far enough away from each other that they do not conflict.
    • look inside the model json file. move all cubes upward.
    • I made a huge forge 1.7.10 mod pack but whenever I try to create a singleplayer world I get the error saying "A fatal error has occurred, this connection is terminated." Does anyone know what the issue could be?  Here is my fml-client-latest.log from when it crashes: https://paste.ubuntu.com/p/3rKSJSqnrX/ and here is the list of mods: https://imgur.com/a/AZifMbg    
    • Im trying to host a minecraft server using the curseforge serverpack from FTB Direwolf20 and when I try to start the server I run into an error The Error: Starting server A problem occurred running the Server launcher.java.lang.reflect.InvocationTargetException         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)         at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)         at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)         at java.lang.reflect.Method.invoke(Unknown Source)         at cpw.mods.fml.relauncher.ServerLaunchWrapper.run(ServerLaunchWrapper.java:43)         at cpw.mods.fml.relauncher.ServerLaunchWrapper.main(ServerLaunchWrapper.java:12) Caused by: java.lang.NoClassDefFoundError: org/apache/logging/log4j/Level         at net.minecraft.launchwrapper.Launch.launch(Launch.java:94)         at net.minecraft.launchwrapper.Launch.main(Launch.java:28)         ... 6 more Caused by: java.lang.ClassNotFoundException: org.apache.logging.log4j.Level         at java.net.URLClassLoader$1.run(Unknown Source)         at java.net.URLClassLoader$1.run(Unknown Source)         at java.security.AccessController.doPrivileged(Native Method)         at java.net.URLClassLoader.findClass(Unknown Source)         at java.lang.ClassLoader.loadClass(Unknown Source)         at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)         at java.lang.ClassLoader.loadClass(Unknown Source)         ... 8 more   I'have tried deleting and downloading the newset version of java wich didnt work and now im using an older version which is the 1.7.0_80 Here is what my Server folder looks like: https://ibb.co/jkbfRY7 Here is what the ServerStart.bat file looks like: @if NOT "%FTB_VERBOSE%"=="yes" ( @echo off ) call settings.bat if NOT EXIST minecraft_server.1.7.10.jar ( goto install ) if NOT EXIST libraries\%LAUNCHWRAPPER% ( goto install ) goto skipinstall :install echo running install script! call FTBInstall.bat :skipinstall REM Check if java in path REM TODO: use %JAVACMD% where java > NUL 2>&1 if %ERRORLEVEL% NEQ 0 ( echo No java binary in path. Can't run server, exiting... pause exit /B ) REM Test JVM REM e.g. 32-bit JVM does not have server\jvm.dll library java -server -version > java-test.log 2>&1 if %ERRORLEVEL% NEQ 0 ( echo Detected following JVM error: echo ======================================= more java-test.log echo ======================================= echo JVM test failed. Can't run server, Exiting... pause exit /B ) if not exist eula.txt ( echo Missing eula.txt. Startup will fail and eula.txt will be created echo Make sure to read eula.txt before playing! goto startserver ) find "eula=false" eula.txt 1 > NUL 2>&1 if %ERRORLEVEL% EQU 0 ( echo Make sure to read eula.txt before playing! Exiting. pause exit /B ) del /f /q autostart.stamp > nul 2>1 :startserver echo Starting server java -server -Xms512M -Xmx2048M -XX:PermSize=256M -XX:+UseParNewGC -XX:+CMSIncrementalPacing -XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -jar FTBServer-1.7.10-1558.jar nogui :server_loop if exist autostart.stamp ( del /f /q autostart.stamp > nul 2>1 echo If you want to completely stop the server process now, press Ctrl+C before the time is up! for /l %%i in (5,-1,1) do ( echo Restarting server in %%i choice /t 1 /d y > nul ) echo Starting server now java -server -Xms512M -Xmx2048M -XX:PermSize=256M -XX:+UseParNewGC -XX:+CMSIncrementalPacing -XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -jar FTBServer-1.7.10-1558.jar nogui echo Server process finished goto :server_loop ) echo Exiting... pause  
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.