Jump to content

Distinguish singleplayer vs. multiplayer


solitone

Recommended Posts

I'm trying to fix the PythonTool-Mod so that it can run correctly also in a multiplayer game (currently it works well only in singleplayer). At the moment it is for 1.10.2, although perhaps  one day I'll try to update it to a more recent version. Basically this mod allows the player to run a python programs, saved on the client machine. It depends on raspberryjammod to launch the .py program, via a '/python script.py' command.

 

In singleplayer mode this works smoothly. However, in multiplayer it doesn't, since it can't locate the python files. Sure, I could copy the .py files on the server, but I think it would be much better if PythonTool-Mod took the .py file from the client machine. Raspberryjammod allows to do this via an alternative command--i.e. 'lpython script.py' ('l' stands for local). But to do thisI need to recognize a singleplayer game from a multiplayer game, so that I can run alternative raspberryjammod commands.

 

I've tried something like the following, and apparently works. However it seems a bit contort. Is there a better way to accomplish the same result?

 

if (world.isRemote) {
	// client side
	if (!Minecraft.getMinecraft().isSingleplayer()) {
		// client talks to dedicated server (multiplayer game)	
		String scriptName = nbtTagCompound.getString("scriptName");
		ClientCommandHandler.instance.executeCommand(player,
			"/lpython " + scriptName);
	}
} else {
	// server side
	if (!FMLCommonHandler.instance().getMinecraftServerInstance().isDedicatedServer()) {
		// server is integrated (singleplayer game)
		String scriptName = nbtTagCompound.getString("scriptName");
		world.getMinecraftServer().getCommandManager().executeCommand(player,
		"/python " + scriptName);
	}
}

 

 

 

Edited by solitone
Link to comment
Share on other sites

53 minutes ago, solitone said:

if (world.isRemote) { // client side if (!Minecraft.getMinecraft().isSingleplayer()) {

Checking if the world is remote before doing client side things does not stop the server from crashing because the JVM does not know what that check cannot return true. In fact, it will crash before ever getting to this line. It crashes when the class is first loaded because it has to check to make sure it knows where all of the classes it loads the JVM knows where to find them. And it goes "Minecraft, Minecraft, OH GOD HELP ME JESUS, I CAN'T FIND THIS CLASS!" and dies.

Edited by Draco18s
  • Like 1

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.

Link to comment
Share on other sites

So what would be the correct solution (in 1.10.2)?I thought my code was bad, but not completely broken, since in fact I don't get any NoClassDefFoundError or ClassNotFoundException, and the server doesn't crash. By contrast, I notice that the following code (originally provided with the mod, in the ComputerBlock class) does cause both those exceptions (even though the server doesn't crash either):

 

public void breakBlock(World worldIn, BlockPos pos, IBlockState state) {
		// If not in creative mode: survival, etc. break and drop the block itself
		if (!Minecraft.getMinecraft().thePlayer.capabilities.isCreativeMode) {
			// Make the block drop itself 
			// [...]
			// Give it a random drop speed
			// [...]
			// Spawn the item in the world
			// [...]
			// Super MUST be called last because it removes the tile entity
			super.breakBlock(worldIn, pos, state);
		} else {
			// If in creative mode, don't drop the block
			super.breakBlock(worldIn, pos, state);
		}
}

 

Edited by solitone
Link to comment
Share on other sites

40 minutes ago, solitone said:

So what would be the correct solution (in 1.10.2)?I thought my code was bad, but not completely broken, since in fact I don't get any NoClassDefFoundError or ClassNotFoundException, and the server doesn't crash. By contrast, I notice that the following code (originally provided with the mod, in the ComputerBlock class) does cause both those exceptions (even though the server doesn't crash either):

 


public void breakBlock(World worldIn, BlockPos pos, IBlockState state) {
		// If not in creative mode: survival, etc. break and drop the block itself
		if (!Minecraft.getMinecraft().thePlayer.capabilities.isCreativeMode) {
			// Make the block drop itself 
			// [...]
			// Give it a random drop speed
			// [...]
			// Spawn the item in the world
			// [...]
			// Super MUST be called last because it removes the tile entity
			super.breakBlock(worldIn, pos, state);
		} else {
			// If in creative mode, don't drop the block
			super.breakBlock(worldIn, pos, state);
		}
}

 

That code from the original mod is not going to work regardless of the side it is on, as spawning ItemEntity in the world must be done on the server side. However, the Minecraft class (used in your if statement) is client side only.

 

In your case, you might want to look at how proxies work.

Edited by DavidM
  • Like 1

Some tips:

Spoiler

Modder Support:

Spoiler

1. Do not follow tutorials on YouTube, especially TechnoVision (previously called Loremaster) and HarryTalks, due to their promotion of bad practice and usage of outdated code.

2. Always post your code.

3. Never copy and paste code. You won't learn anything from doing that.

4. 

Quote

Programming via Eclipse's hotfixes will get you nowhere

5. Learn to use your IDE, especially the debugger.

6.

Quote

The "picture that's worth 1000 words" only works if there's an obvious problem or a freehand red circle around it.

Support & Bug Reports:

Spoiler

1. Read the EAQ before asking for help. Remember to provide the appropriate log(s).

2. Versions below 1.11 are no longer supported due to their age. Update to a modern version of Minecraft to receive support.

 

 

Link to comment
Share on other sites

5 hours ago, solitone said:


So doesn’t it cause the server to crash, in contrast to what Draco18s said?

It will cause the server to crash, as such class does not exist on the server side.

  • Like 1

Some tips:

Spoiler

Modder Support:

Spoiler

1. Do not follow tutorials on YouTube, especially TechnoVision (previously called Loremaster) and HarryTalks, due to their promotion of bad practice and usage of outdated code.

2. Always post your code.

3. Never copy and paste code. You won't learn anything from doing that.

4. 

Quote

Programming via Eclipse's hotfixes will get you nowhere

5. Learn to use your IDE, especially the debugger.

6.

Quote

The "picture that's worth 1000 words" only works if there's an obvious problem or a freehand red circle around it.

Support & Bug Reports:

Spoiler

1. Read the EAQ before asking for help. Remember to provide the appropriate log(s).

2. Versions below 1.11 are no longer supported due to their age. Update to a modern version of Minecraft to receive support.

 

 

Link to comment
Share on other sites

17 hours ago, DavidM said:

It will cause the server to crash, as such class does not exist on the server side.

Ok, although I can’t crash the server. I don’t even get an exception with my code. And when I get an exception (when I break a computer block and the breakBlock method is executed) the server does not crash.

 

I’m not objecting what you’re saying. I’m just confused. I’m trying to understand why I don’t crash the server. Is it because I’m testing it running both the server and the client through IntelliJ IDEA (i.e. via runServer and runClient Gradle tasks)? Still, I have also tried with client and server running on two different machines, and the breakBlock method does not crash the server, it just throw an uncaught exception. So perhaps does it depend on the java version?

 

Thanks

Edited by solitone
Link to comment
Share on other sites

I’ve repeated the test again using a remote server running on a separate machine. The code fragment in my original post does not cause any exception. By contrast, the breakBlock method (which I didn’t change) does cause a ClassNotFoundException. Such a behaviour contrasts what I would expect, based on what you said. I have no clue about what could exmplain this difference, but clearly it’s not related to the deployment scenario (both client and server on the same development machine vs. client and server in separate machines). 

Link to comment
Share on other sites

As you did not provide very much code...

 

Who knows.

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.

Link to comment
Share on other sites

This is the code fragment I wrote and that you said would crash the server:

if (world.isRemote) {
	// client side
	if (!Minecraft.getMinecraft().isSingleplayer()) {
		// client talks to dedicated server (multiplayer game)	
		String scriptName = nbtTagCompound.getString("scriptName");
		ClientCommandHandler.instance.executeCommand(player,
			"/lpython " + scriptName);
	}
} else {
	// server side
	if (!FMLCommonHandler.instance().getMinecraftServerInstance().isDedicatedServer()) {
		// server is integrated (singleplayer game)
		String scriptName = nbtTagCompound.getString("scriptName");
		world.getMinecraftServer().getCommandManager().executeCommand(player,
		"/python " + scriptName);
	}
}

 

The point you made is that, as soon as the JVM loads the class containing this code, the JVM checks all referenced classes are available. Since Minecraft class is not available on the dedicated server, an exception should be raised and the server should crash.

 

What I test this code, however, I don't experience any exception. The behaviour I observe is different to the expected behaviour you described. It is as if the JVM looks for the referenced classes when they need to be executed--i.e. when world.isRemote is true, which cannot happen on a dedicated server.

 

This hypothesis is confirmed by the following code, which is delivered with the original version of the mod (i.e. I didn't change anything in it):

 

public void breakBlock(World worldIn, BlockPos pos, IBlockState state) {
		// If not in creative mode: survival, etc. break and drop the block itself
		if (!Minecraft.getMinecraft().thePlayer.capabilities.isCreativeMode) {
			// Make the block drop itself 
			// [...]
			// Give it a random drop speed
			// [...]
			// Spawn the item in the world
			// [...]
			// Super MUST be called last because it removes the tile entity
			super.breakBlock(worldIn, pos, state);
		} else {
			// If in creative mode, don't drop the block
			super.breakBlock(worldIn, pos, state);
		}
}

 

This code does not cause an exception when the containing class is loaded, but only when the method is actually called-i.e. when I break a ComputerBlock (a block provided with this mod). When the method is called, I get an exception on the dedicated server:

[06:33:32] [Server thread/FATAL] [net.minecraft.server.MinecraftServer]: Error executing task
java.util.concurrent.ExecutionException: java.lang.NoClassDefFoundError: net/minecraft/client/Minecraft
	at java.util.concurrent.FutureTask.report(FutureTask.java:122) ~[?:1.8.0_232]
	at java.util.concurrent.FutureTask.get(FutureTask.java:192) ~[?:1.8.0_232]
	at net.minecraft.util.Util.runTask(Util.java:29) [Util.class:?]
	at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:743) [MinecraftServer.class:?]
	at net.minecraft.server.dedicated.DedicatedServer.updateTimeLightAndEntities(DedicatedServer.java:408) [DedicatedServer.class:?]
	at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:688) [MinecraftServer.class:?]
	at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:537) [MinecraftServer.class:?]
	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_232]
Caused by: java.lang.NoClassDefFoundError: net/minecraft/client/Minecraft
	at pythontool.computerblock.ComputerBlock.breakBlock(ComputerBlock.java:326) ~[ComputerBlock.class:?]
	at net.minecraft.world.chunk.Chunk.setBlockState(Chunk.java:613) ~[Chunk.class:?]
	at net.minecraft.world.World.setBlockState(World.java:386) ~[World.class:?]
	at net.minecraft.block.Block.removedByPlayer(Block.java:1317) ~[Block.class:?]
	at net.minecraft.server.management.PlayerInteractionManager.removeBlock(PlayerInteractionManager.java:298) ~[PlayerInteractionManager.class:?]
	at net.minecraft.server.management.PlayerInteractionManager.removeBlock(PlayerInteractionManager.java:292) ~[PlayerInteractionManager.class:?]
	at net.minecraft.server.management.PlayerInteractionManager.tryHarvestBlock(PlayerInteractionManager.java:339) ~[PlayerInteractionManager.class:?]
	at net.minecraft.server.management.PlayerInteractionManager.onBlockClicked(PlayerInteractionManager.java:175) ~[PlayerInteractionManager.class:?]
	at net.minecraft.network.NetHandlerPlayServer.processPlayerDigging(NetHandlerPlayServer.java:658) ~[NetHandlerPlayServer.class:?]
	at net.minecraft.network.play.client.CPacketPlayerDigging.processPacket(CPacketPlayerDigging.java:56) ~[CPacketPlayerDigging.class:?]
	at net.minecraft.network.play.client.CPacketPlayerDigging.processPacket(CPacketPlayerDigging.java:12) ~[CPacketPlayerDigging.class:?]
	at net.minecraft.network.PacketThreadUtil$1.run(PacketThreadUtil.java:21) ~[PacketThreadUtil$1.class:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[?:1.8.0_232]
	at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[?:1.8.0_232]
	at net.minecraft.util.Util.runTask(Util.java:28) ~[Util.class:?]
	... 5 more
Caused by: java.lang.ClassNotFoundException: net.minecraft.client.Minecraft
	at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:101) ~[launchwrapper-1.12.jar:?]
	at java.lang.ClassLoader.loadClass(ClassLoader.java:418) ~[?:1.8.0_232]
	at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[?:1.8.0_232]
	at pythontool.computerblock.ComputerBlock.breakBlock(ComputerBlock.java:326) ~[ComputerBlock.class:?]
	at net.minecraft.world.chunk.Chunk.setBlockState(Chunk.java:613) ~[Chunk.class:?]
	at net.minecraft.world.World.setBlockState(World.java:386) ~[World.class:?]
	at net.minecraft.block.Block.removedByPlayer(Block.java:1317) ~[Block.class:?]
	at net.minecraft.server.management.PlayerInteractionManager.removeBlock(PlayerInteractionManager.java:298) ~[PlayerInteractionManager.class:?]
	at net.minecraft.server.management.PlayerInteractionManager.removeBlock(PlayerInteractionManager.java:292) ~[PlayerInteractionManager.class:?]
	at net.minecraft.server.management.PlayerInteractionManager.tryHarvestBlock(PlayerInteractionManager.java:339) ~[PlayerInteractionManager.class:?]
	at net.minecraft.server.management.PlayerInteractionManager.onBlockClicked(PlayerInteractionManager.java:175) ~[PlayerInteractionManager.class:?]
	at net.minecraft.network.NetHandlerPlayServer.processPlayerDigging(NetHandlerPlayServer.java:658) ~[NetHandlerPlayServer.class:?]
	at net.minecraft.network.play.client.CPacketPlayerDigging.processPacket(CPacketPlayerDigging.java:56) ~[CPacketPlayerDigging.class:?]
	at net.minecraft.network.play.client.CPacketPlayerDigging.processPacket(CPacketPlayerDigging.java:12) ~[CPacketPlayerDigging.class:?]
	at net.minecraft.network.PacketThreadUtil$1.run(PacketThreadUtil.java:21) ~[PacketThreadUtil$1.class:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[?:1.8.0_232]
	at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[?:1.8.0_232]
	at net.minecraft.util.Util.runTask(Util.java:28) ~[Util.class:?]
	... 5 more

 

The server doesn't crash though, and I can continue playing.

 

To sum up, I'd like to understand why in my case I don't experience the expected behaviour.

 

Link to comment
Share on other sites

You can try building the mod and running a Forge server with it. This would cause a crash once the class referencing client-only components are loaded.

I am not sure why servers started with runServer do not remove client-specific classes, but those classes will be removed on server side outside of development, thus causing a crash.

Some tips:

Spoiler

Modder Support:

Spoiler

1. Do not follow tutorials on YouTube, especially TechnoVision (previously called Loremaster) and HarryTalks, due to their promotion of bad practice and usage of outdated code.

2. Always post your code.

3. Never copy and paste code. You won't learn anything from doing that.

4. 

Quote

Programming via Eclipse's hotfixes will get you nowhere

5. Learn to use your IDE, especially the debugger.

6.

Quote

The "picture that's worth 1000 words" only works if there's an obvious problem or a freehand red circle around it.

Support & Bug Reports:

Spoiler

1. Read the EAQ before asking for help. Remember to provide the appropriate log(s).

2. Versions below 1.11 are no longer supported due to their age. Update to a modern version of Minecraft to receive support.

 

 

Link to comment
Share on other sites

14 hours ago, DavidM said:

You can try building the mod and running a Forge server with it. This would cause a crash once the class referencing client-only components are loaded.

I am not sure why servers started with runServer do not remove client-specific classes, but those classes will be removed on server side outside of development, thus causing a crash.

I suspected it was related to grade's runServer task. However, I also tested the mod on a Forge server (running in a separate host BTW), and I do not experience any crash. My code fragment doesn't cause any exception either. I only get an exception when I break a ComputerBlock--i.e. when the breakBlock is called, not when the class is loaded. 

 

Could it depend on java version? I am on java 8.

Edited by solitone
Link to comment
Share on other sites

On 12/6/2019 at 7:14 AM, DavidM said:

you might want to look at how proxies work.

 

From what I see in the examples I've found, proxies are basically used for preInitialization, Inizialization, and postInizialization tasks. 

 

Here I've got an Item class, with method onItemRightClick() that should perform different things based on the game mode (multiplayer vs. singleplayer).

 

How would I take advantage of the sided proxies to refactor the following class? Should I have two classes, one for the client, the other for the dedicated server, and register the first class on the client, and the second on the dedicated server?

 

I'm confused and basically stuck.

 

public class ScriptItem extends Item {
	// [...]

	@Override
	public ActionResult<ItemStack> onItemRightClick(ItemStack stack, World world, EntityPlayer player, EnumHand hand)	{
		// [...]

		String separator = getSeparator();
		if (world.isRemote) {
			// client side
			if (!Minecraft.getMinecraft().isSingleplayer()) {
				// client talks to dedicated server (multiplayer game)
				String scriptName = nbtTagCompound.getString("scriptName");
				ClientCommandHandler.instance.executeCommand(player,
						"/lpython " + "pythontool" + separator + scriptName);
			}
		} else {
			// server side
			if (!FMLCommonHandler.instance().getMinecraftServerInstance().isDedicatedServer()) {
				// server is integrated (singleplayer game)
				String scriptName = nbtTagCompound.getString("scriptName");
				world.getMinecraftServer().getCommandManager().executeCommand(player,
						"/python " + "pythontool" + separator + scriptName);
			}
		}
}

 

Link to comment
Share on other sites

32 minutes ago, solitone said:

From what I see in the examples I've found, proxies are basically used for preInitialization, Inizialization, and postInizialization tasks. 

And all of those examples are terrible. Because all three of those things are main mod class tasks.

Check out this and this instead. Or even better, this.

35 minutes ago, solitone said:

How would I take advantage of the sided proxies to refactor the following class? Should I have two classes, one for the client, the other for the dedicated server

Yes. That's how proxies work.

 

  • Like 1

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.

Link to comment
Share on other sites

2 hours ago, Draco18s said:

That's how proxies work.

 

So I would have ServerScriptItem and ClientScriptItem, both inheriting from ScriptItem, and I would register a ServerScriptItem object on the dedicated server and a ClientScriptItem object on the client?

Edited by solitone
Link to comment
Share on other sites

Items are not proxies.

Proxies are proxies, Items are Items.

The Item is supposed to call a method in the proxy, it is not the proxy itself.

  • Like 1

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.

Link to comment
Share on other sites

5 hours ago, Draco18s said:

The Item is supposed to call a method in the proxy, it is not the proxy itself.

 

OK, thanks, that was helpful. 

As for @SidedProxyvs. DistExecutor, if I understand it right the former was used till version 1.12, while the latter with version 1.13+, right?

Link to comment
Share on other sites

@Override
	public ActionResult<ItemStack> onItemRightClick(ItemStack stack, World world, EntityPlayer player, EnumHand hand)	{
		// [...]
		String separator = getSeparator();
		String scriptName = nbtTagCompound.getString("scriptName");
		String scriptPath = "pythontool" + separator + scriptName;
		proxy.runPython(world, player, scriptPath);
  		// [...]
	}

 

^^^ This is how I refactored onItemRightClick(). The runPython() method does nothing on the dedicated server, while on the client:

 

public class ClientOnlyProxy extends CommonProxy
{
// [...]
@Override
	public void runPython(World world, EntityPlayer player, String scriptPath) {
		super.runPython(world, player, scriptPath);
		if (world.isRemote) {
			// client side
			if (!Minecraft.getMinecraft().isSingleplayer()) {
				// client talks to dedicated server (multiplayer game)
				ClientCommandHandler.instance.executeCommand(player,
						"/lpython " + scriptPath);
			}
		} else {
			// server side
			if (player.isSneaking()) { // shift pressed. Run new parallel script
				Minecraft.getMinecraft().thePlayer.getServer().getCommandManager().executeCommand(player,
						"/apy " + scriptPath);
			} else { // shift not pressed. Cancel previous scripts and run new script
				world.getMinecraftServer().getCommandManager().executeCommand(player,
						"/python " + scriptPath);
			}
		}
	}
}

 

I still need to figure out why they used two different approaches to execute commands on the integrated server--Minecraft.getMinecraft().thePlayer.getServer().getCommandManager().executeCommand() vs. world.getMinecraftServer().getCommandManager().executeCommand().

 

public abstract class CommonProxy {
// [...]
public void runPython(World world, EntityPlayer player, String scriptPath) {}
}

 

public class PythonTool {
	// [...]
	@SidedProxy(clientSide="pythontool.ClientOnlyProxy", serverSide="pythontool.DedicatedServerProxy")
	public static CommonProxy proxy;
	// [...]
}

 

Are still there significant mistakes? Thanks again!

Link to comment
Share on other sites

47 minutes ago, solitone said:

if (world.isRemote) {

This will always be true on the client

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.

Link to comment
Share on other sites

10 hours ago, Draco18s said:

This will always be true on the client

 

As far as I understand, FML instantiates one of the two proxies based on the pyhisical side [1]. So ClientOnlyProxy (that I probably should rename ClientProxy) is instantiated in the physical client, which comprises both a logical client (where world.isRemote is true) and a logical server (i.e. the integrated server, where world.isRemote is false [2]).

 

Am I missing something?

Edited by solitone
Link to comment
Share on other sites

Some logging that should clear things up:

 

public class ClientOnlyProxy extends CommonProxy
{
	private static final Logger LOGGER = LogManager.getLogger();	
	// [...]
	@Override
	public void runPython(World world, EntityPlayer player, String scriptPath) {
		LOGGER.info("In runPython() (physical client).");
		if (world.isRemote) {
			// client side
			LOGGER.info("World is remote - > logical client.");
			if (!Minecraft.getMinecraft().isSingleplayer()) {
				LOGGER.info("Multiplayer game: run py script from client.");
				// client talks to dedicated server (multiplayer game)
				ClientCommandHandler.instance.executeCommand(player,
						"/lpython " + scriptPath);
			}
		} else {
			// server side
			LOGGER.info("World is NOT remote -> logical server (integrated).");
			LOGGER.info("Singleplayer game: run py script from server.");
			if (player.isSneaking()) { // shift pressed. Run new parallel script
				Minecraft.getMinecraft().thePlayer.getServer().getCommandManager().executeCommand(player,
						"/apy " + scriptPath);
			} else { // shift not pressed. Cancel previous scripts and run new script
				world.getMinecraftServer().getCommandManager().executeCommand(player,
						"/python " + scriptPath);
			}
		}
	}
}

 

Here's the output when playing a singleplayer game, showing that the runPython() method is called twice--once from the logical client and once from the logical (integrated) server:

 

[17:17:05] [Client thread/INFO] [pythontool.ClientOnlyProxy]: In runPython() (physical client).
[17:17:05] [Client thread/INFO] [pythontool.ClientOnlyProxy]: World is remote - > logical client.
[17:17:05] [Server thread/INFO] [pythontool.ClientOnlyProxy]: In runPython() (physical client).
[17:17:05] [Server thread/INFO] [pythontool.ClientOnlyProxy]: World is NOT remote -> logical server (integrated).
[17:17:05] [Server thread/INFO] [pythontool.ClientOnlyProxy]: Singleplayer game: run py script from server.
[17:17:05] [Server thread/INFO] [STDOUT]: [mobi.omegacentauri.raspberryjammod.ScriptExternalCommand:execute:275]: Running mcpipy/pythontool/donut.py

 

BTW is there a way to show logging messages with level < INFO? 

Edited by solitone
Link to comment
Share on other sites

You'll note that your code is being called twice on the integrated server now: once from the logical client side (which sends a command, whichlikely makes the server execute code) and once from the logical server side. 

Edited by Draco18s

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.

Link to comment
Share on other sites

16 minutes ago, solitone said:

This isn’t an issue but normal behaviour, is it?

No. Your client code is sending information to make the server do things.

Your server code is telling the server to do those same things (again).

  • Like 1

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.

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
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.