Jump to content

Recommended Posts

Posted (edited)

Hello!

I was wondering, if I call a method in a server-side method where only the server thread runs, will the contents in the method be run by the server and not the client?

For example:

public void onCommand(EntityPlayer playerIn)
{
  World worldIn = playerIn.worldObj;
  worldIn.playSound(null, playerIn.getPosition(), SoundEvents.BLOCK_CLOTH_BREAK, SoundCategory.PLAYERS, 1.0F, 1.0F);
  Random rand = worldIn.rand;
  worldIn.spawnParticle(EnumParticleTypes.CLOUD, 
       playerIn.posX + (double)(rand.nextFloat() * playerIn.width * 2.5F) - (double)playerIn.width, 
       playerIn.posY + 0.5D + (double)(rand.nextFloat() * playerIn.height) - 1.25D, 
       playerIn.posZ + (double)(rand.nextFloat() * playerIn.width * 2.5F) - (double)playerIn.width, 
       rand.nextGaussian() * 0.025D, rand.nextGaussian() * 0.025D, rand.nextGaussian() * 0.025D, 1
    );
  
  DinocraftPlayer player = DinocraftPlayer.getEntityPlayer(playerIn);
            	
  if (player != null)
  {
    player.setMaxHealth(playerIn.getMaxHealth() + 1.0F);
  }
}

@Override
public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException 
{
  EntityPlayer playerIn = getCommandSenderAsPlayer(sender);
  this.onCommand(playerIn); // when I call this method, will the contents inside the method run on the server-thread, client-thread, or common (client and server-side)?
}

This is just a quick example.

 

Any help will be welcome.

Thanks! :)

Edited by Differentiation
Posted

Okay, let me give you a high-level explanation of this whole "sides" stuff.

 

Whenever you make a client and server game you don't want people to be able to cheat. Therefore you want all game logic to happen on the server, otherwise people would create clients that would do things like allow them to teleport or do extra damage and such. So ideally every multi-player game would have all logic on the server and the client would only do user interface (graphics, sounds and input from keyboard and mouse).

 

However, if you try to make a game where the client only does user interface you'll quickly find that the movement is not smooth. This is because the graphics updates faster than the network can send the information from the server. So every real-time game has to figure out a way where the client does some of the processing in between updates from the server.

 

Unfortunately, because the game is complicated for the client to smooth things out graphically it needs to actually process some of the logic while waiting for updates.

 

That is the general idea. But then in Minecraft there are a couple specific additional things that cause confusion.

 

In order to optimize things like memory use, they decided it would be good to not load things that are not needed. So they used the "sided" annotation. When a class or field or method is annotated as Side.CLIENT then the server doesn't have to load it and saves memory. 

 

That would be easy to understand except there is one other thing. Normally your client and server will run in separate Java machine instances. However, that is a bit wasteful when playing in single player. So instead they decided to combine them into a single Java instance (integrated server).

 

The problem with the integrated server is that because it is a single Java machine running both sides then the classes for both sides are loaded -- basically the sided annotation is pretty much ignored. Yes there are two threads, but they are in one JVM. This causes issues for novice modders because if they write code that "reaches across the sides" it will still appear to function without error. A lot of modders will test in integrated server mode and so won't realize the problem and then get yelled at when they post their code on the forum.

 

So a very important tip for modding is always test your mod by running with a dedicated server. You can do this easily in Eclipse by first running the Server run configuration and then while that is running run the Client run configuration. Then in your client game you choose connect to server and put in the "loopback" address 127:0:0:1.  If you test like this, you'll very quickly learn when you are making mistakes with sided functionality.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted
11 minutes ago, jabelar said:

In order to optimize things like memory use, they decided it would be good to not load things that are not needed. So they used the "sided" annotation. When a class or field or method is annotated as Side.CLIENT then the server doesn't have to load it and saves memory.

More specifically, the class isn't even available. The Minecraft dedicated server jar does not include those classes (or fields/methods). They've literally been stripped. Even if the JVM wants them, they aren't there to go get. That's why the server will crash with a "Class Not Found" exception. While the reason for the removal is to make the jar more lightweight, it's more complicated than simply "not loading" things.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted (edited)
3 hours ago, Differentiation said:

I was wondering, if I call a method in a server-side method where only the server thread runs, will the contents in the method be run by the server and not the client?

Okay, back to your original question. So both the server and client are totally separate threads. The only issue with mixing up sides is if you try to access classes that aren't supposed to be available (but might be if you're using integrated server) due to being on the other "side".

 

So methods are only called in the client thread from the client thread. And methods are only called in the server thread from the server thread. However, there are some methods which are part of the logic on both sides and will both get called (separately but in parallel). This is for the reason I explained above -- some logic does need to execute on the client in order to smooth out the action between server updates.

 

However, the client calls it itself. The client is just trying to copy what the server will do.

 

It is actually kinda hard by just looking at the code to know where the code will run. There is very likely code that is not marked as SideOnly that still only runs on one side. And if the code has any checks for world#isRemote then it will execute differently depending on where it will run. Remember, the Side.CLIENT stuff is stripped out to optimize the server JAR size but there is no requirement to strip out everything.

 

In many ways you just need to get a feel for which things are working in each place. One good way to get a feel for that is to make some test classes (block, entity, etc.) that have console statements in the methods of interest and watch what get's printed to the console. You'll see some that happen in one thread or the other, and some that happen in both. 

 

Sometimes things are obvious, like a renderer only being on client side. However, sometimes it gets confusing because the server implementation will use a same or similar method name to notify clients (rather than do the client thing) -- a good example is various sound playing methods where on the client they will directly play the sound, but on server they will send notifications to the clients (to tell them to play the sound).

 

So don't feel too bad if you still get confused. But do try to understand the main concepts:

1) The dedicated server JAR does not have access to anything marked Side.CLIENT, although testing with integrated server will fool you (because it does have access).

2) Methods that are not marked as sided may run on one side or both, and if they run on both may use world#isRemote to have different behavior.

 

P.S. Modders mostly run into problems with Side.CLIENT., not Side.SERVER There are also cases of Side.SERVER but those are mostly limited to networking, user authentication, and a few other MinecraftServer fields, so modders don't seem to run into problems with that much.

 

Edited by jabelar
  • Like 1

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted
6 hours ago, jabelar said:

Okay, back to your original question. So both the server and client are totally separate threads. The only issue with mixing up sides is if you try to access classes that aren't supposed to be available (but might be if you're using integrated server) due to being on the other "side".

 

So methods are only called in the client thread from the client thread. And methods are only called in the server thread from the server thread. However, there are some methods which are part of the logic on both sides and will both get called (separately but in parallel). This is for the reason I explained above -- some logic does need to execute on the client in order to smooth out the action between server updates.

 

However, the client calls it itself. The client is just trying to copy what the server will do.

 

It is actually kinda hard by just looking at the code to know where the code will run. There is very likely code that is not marked as SideOnly that still only runs on one side. And if the code has any checks for world#isRemote then it will execute differently depending on where it will run. Remember, the Side.CLIENT stuff is stripped out to optimize the server JAR size but there is no requirement to strip out everything.

 

In many ways you just need to get a feel for which things are working in each place. One good way to get a feel for that is to make some test classes (block, entity, etc.) that have console statements in the methods of interest and watch what get's printed to the console. You'll see some that happen in one thread or the other, and some that happen in both. 

 

Sometimes things are obvious, like a renderer only being on client side. However, sometimes it gets confusing because the server implementation will use a same or similar method name to notify clients (rather than do the client thing) -- a good example is various sound playing methods where on the client they will directly play the sound, but on server they will send notifications to the clients (to tell them to play the sound).

 

So don't feel too bad if you still get confused. But do try to understand the main concepts:

1) The dedicated server JAR does not have access to anything marked Side.CLIENT, although testing with integrated server will fool you (because it does have access).

2) Methods that are not marked as sided may run on one side or both, and if they run on both may use world#isRemote to have different behavior.

 

P.S. Modders mostly run into problems with Side.CLIENT., not Side.SERVER There are also cases of Side.SERVER but those are mostly limited to networking, user authentication, and a few other MinecraftServer fields, so modders don't seem to run into problems with that much.

 

1 hour ago, diesieben07 said:

I think the confusion mainly comes from the fact, that there are two types of sides, "logical" and "physical". Most of the time you want to think about "logical" side.

By "physical" side I mean "the client launched from the launcher" vs. "the server launched via minecraft_server.jar".

By "logical" side I mean "the thread running the client logic" vs.  "the thread running the server logic".

 

Now, when you start a single player game (in the physical client), the physical client starts two threads, one running a logical client and one running a logical server. This logical server thread is called the integrated server, because it is integrated into the physical client. Since it is running inside the same JVM process, it has access to the logical client thread and all it's resources. Doing so, however, is known as "reaching across logical sides" and is a very bad idea.

 

When you connect to a server, your physical client only spawns one thread, running the logical client, since the logical server runs remotely.

 

The physical server only ever spawns one thread, running the logical server.

 

I hope this clears things up a bit.

Thank you!

You cleared up many things for me. I finally fully understand why Minecraft.getMinecraft(), for example, doesn't work when on a server, and things like that. :)

 

Thanks again!

Happy modding!

Posted (edited)

But then if I run a method in a method that runs on the logical server such as execute(...), will the method that I run inside run on the logical server, the logical client or both, in that case?

Ex.

public void onCommand(EntityPlayer playerIn)
{
  World worldIn = playerIn.worldObj;
  worldIn.playSound(null, playerIn.getPosition(), SoundEvents.BLOCK_CLOTH_BREAK, SoundCategory.PLAYERS, 1.0F, 1.0F);
  
  DinocraftPlayer player = DinocraftPlayer.getEntityPlayer(playerIn);
  player.setMaxHealth(playerIn.getMaxHealth() + 1.0F);
}

@Override
public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException 
{
  EntityPlayer playerIn = getCommandSenderAsPlayer(sender);
  this.onCommand(playerIn); // when I call this method, will the contents inside the method run on the server-thread, client-thread, or common (client and server-side)?
}

Thanks!

Edited by Differentiation
Posted
6 minutes ago, diesieben07 said:

I think you are lacking a basic understanding of how threads work and you should look into that. A thread is a chain of instructions. If you call a method, that method runs on the same thread.

I mean, yeah, I was expecting it to run on the same thread.

Thanks!

Posted

(Note that there are clean ways of reaching across threads in multithreaded applications, but none of them apply to Minecraft because of the physical sided nature of things: you want it to work on a dedicated server as well, then you can't reach across, even cleanly. The only way to do so is with packets, and if you look at the packet documentaiton, you'll see that one of those clean methods of reaching across is utilized, because surprise! There's another thread running: the netcode thread).

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

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
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
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.

Announcements



×
×
  • Create New...

Important Information

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