Jump to content

Forge MP, Bukkit and Minecraft 1.3


Kinniken

Recommended Posts

In eclipse you can have linked source files, and debugging in eclipse will pull all source files that are linked and compile them.

It only because a issue when you go to reobf, in which case you do exactly what you said,

Make copy of MCP/src to MCP/src-bak

Copy Mod/Client -> MCP/src/minecraft

Copy Mod/Common -> MCP/src/minecraft

Copy Mod/Server -> MCP/src/minecraft_server

Copy Mod/Common -> MCP/src/minecraft_server

Recompile, reobf

Del MCP/src

Move MCP/src-bak -> MCP/src

Small batch file to do that makes it simple.

 

Thanks, that should work fine. Though using linked source folders means that I can't use SVN in those projects. I can always have separate projects for that though. Or maybe it's time to move to Git. Does eGit work with linked source directories? And is it simple to use to keep in sync two dev environments? I currently use SVN partly for backup/history but also mostly to move changes from my laptop to desktop and vice-versa as I code on both.

Link to comment
Share on other sites

  • Replies 102
  • Created
  • Last Reply

Top Posters In This Topic

If you look in my projects you'll see there's an ant build script that can help by pushing all the "manual" work of rebuilding/reobfuscating the code for both client and server. (I also have an unshared version that is tentatively pushing a bukkit build too ;) ).

 

Thanks, I'll check that out! And I'm not yet worrying about Bukkit support but when that comes I might like a look at that script ;) Should be possible to integrate that with my own bash packaging scripts too.

 

I recommend you start by putting everything in common and then just peeling out enough that client and server compile.

 

I also strongly recommend you use your own packages for your mod. that way you don't clutter up the net.minecraft.src package namespace.

 

I did both yesterday. For the packages, I had actually started in my own package when I started developing Millénaire but had stopped when I realised I'd be accessing lots of protected MC variables. I don't know if anything changed in the MC code though but when moving my code yesterday I found out that ultimately there's only a dozen protected members/methods I need access too, which is few enough that a couple of utility methods in one class in the main package can handle fine.

 

Finally, the @SidedProxy is useful (for me) because it lets the mod loader load in the right "sided" class for client or server into my mod. I use that as a proxy to access side specific behaviour without having to code duplication everywhere.

 

Yeah, I'll probably do something similar, maybe not with the annotations but at least with a common interface or parent class and then client and server implementations. In fact I was thinking of also having one for single player, to isolate that code - when 1.3 comes out it will probably have to be removed so might as well centralise it instead of mixing it with the client.

 

Anyway, I haven't really looked at the Forge MP APIs yet, so far I've been focusing on splitting my code and planning how to make Millénaire multiplayer (functionally-speaking). There are aspects like missions or the language system that I designed with only one player in mind and which are a little tricky to make multiplayer. I'll surely have more questions when I get to the actual networking code.

 

Otherwise, small not-Forge-related question - anyone know how to get Eclipse to load files from MCP/bin when launching the client from Eclipse itself? I have all my skins and textures there and when running Minecraft from Eclipse I get errors due to them being missing (I have my own Eclipse project BTW, I do not use the MCP-provided workspace). Alternatively, is there a way to store textures and skins outside /bin? That would also make it easier for Millénaire modders, that way any skin they need to add could go in the same directory as the other Millénaire files.

Link to comment
Share on other sites

Toss your resources into a zip and toss them into the jars/mods folder, FML loads that into the class path so you should be able to access them just fine.

 

As for the whole having to get linked folders and stuff into git or svn, just don't use the SVN stuff inside eclipse, Forge just uses a folder inside the MCP workspace as the git root.

So you have MCP/Millénaire/{stuff in svn}

 

For the languages, just send the client a key and have them translate it to the full string depending on there selected language. This has the added benefit of minimizing the length text sent to the client.

I do Forge for free, however the servers to run it arn't free, so anything is appreciated.
Consider supporting the team on Patreon

Link to comment
Share on other sites

Toss your resources into a zip and toss them into the jars/mods folder, FML loads that into the class path so you should be able to access them just fine.

 

Can it work without zipping? Would be easiest for users.

 

As for the whole having to get linked folders and stuff into git or svn, just don't use the SVN stuff inside eclipse, Forge just uses a folder inside the MCP workspace as the git root.

So you have MCP/Millénaire/{stuff in svn}

 

I could, but having SVN inside Eclipse is convenient. Well, that's minor.

 

For the languages, just send the client a key and have them translate it to the full string depending on there selected language. This has the added benefit of minimizing the length text sent to the client.

 

That was my first idea but it has significant drawbacks. It means that any building or quest present on the server must also exist on the client. That means that I can't add any without breaking client/server compatibility, and that the server operator cannot add custom content to the server. Even if it means sending more text I think I'll have to go for server-side translations for quite a few things. In turns that means I must overhaul Minecraft's translation system, as currently on the main language and backup language are loaded at any point - server-side that won't work. Anyway, that's problems in my own code, not with Forge ;)

Link to comment
Share on other sites

Well you should be able to toss your resources in anywhere along the class path, as long as java knows where it is.

Having it in a zip in the mods folder is the simplest method to make sure its in the same configuration as it would be when you do the release.

However, you would try making a resources linked folder in eclipse, and make sure that that is treated as a source folder and the files are copied to the bin folder when you debug. There are a bunch of ways to do it, just none to simple or intuitive.

 

Meh, with the way MCP is setup, and everything, doing the repo management from inside eclipse is a pain.

 

As for your languages, there are a few issues, You'll have to have the client tell the server what language it is. And then the server would have to translate in a per-player bases.

 

You may want to write a system where when a player connects, it asks the server for the latest version of the translation file for it's language. And if they are out of sync, the client downloads it from the server.

 

That would allow your admins to write custom phrases and translations, and the client would download it on the fly.

 

Personally, I think that the server should have no concept of language and translation. Except for system messages aimed twards the server admin in the log. If you are wanting something displayed to the client it should only be known to the server as a key.

I do Forge for free, however the servers to run it arn't free, so anything is appreciated.
Consider supporting the team on Patreon

Link to comment
Share on other sites

Well you should be able to toss your resources in anywhere along the class path, as long as java knows where it is.

Having it in a zip in the mods folder is the simplest method to make sure its in the same configuration as it would be when you do the release.

However, you would try making a resources linked folder in eclipse, and make sure that that is treated as a source folder and the files are copied to the bin folder when you debug. There are a bunch of ways to do it, just none to simple or intuitive.

 

Ok, will try.

 

As for your languages, there are a few issues, You'll have to have the client tell the server what language it is. And then the server would have to translate in a per-player bases.

 

That's what I'm thinking of. Not ideal but the best in my case.

 

You may want to write a system where when a player connects, it asks the server for the latest version of the translation file for it's language. And if they are out of sync, the client downloads it from the server.

 

That would allow your admins to write custom phrases and translations, and the client would download it on the fly.

 

Personally, I think that the server should have no concept of language and translation. Except for system messages aimed twards the server admin in the log. If you are wanting something displayed to the client it should only be known to the server as a key.

 

That's a good principle, but tricky for a mod like mine that can have sub-mods written for it. There's not one "translation file", there are several for the main content and more for each potential sub-mod. In fact if I go that way I might as well do full transfer of sub-mods to the client, that way I'll solve the villager skin problem too (that any villagers added to the server that require new skins will not get displayed on the client if he doesn't have them as well). However that's best left to a future update, I should get the basic SMP working first ;)

 

Otherwise, do you know of any well-written MP GUI that's not container-based that I could look at?

Link to comment
Share on other sites

Well having a full blown file transfer system for your mod from the server isn't to bad of a idea, nor is it particularly difficult.

Anyways,  All server side GUIs are containers, you will probably have to write something quite special for some of your GUI's.

It's been to long since I've played your mod to determine which specific types of GUIs you're referring to. What is your GUI needing to do?

I do Forge for free, however the servers to run it arn't free, so anything is appreciated.
Consider supporting the team on Patreon

Link to comment
Share on other sites

Ah, didn't know that. Some of my GUIs are container-based to some extent (like the trade one), but some have nothing whatsoever to do with containers. They are all subclasses of a "GuiText" class of mine, taking as input pages of text with various buttons. They are used for example for quests (display infos on the current step, allow the player to accept or refuse), to buy buildings from a village, or to influence diplomatic relations between villages. Basically I'll need a way to send the pages to the client and the button press back to the server (most of them having server-side effects).

 

I also have some that are more or less container-based, such as the trade interface and my puja enchanting system. However in both cases I need more data than just the inventory of the container and that of the player.

Link to comment
Share on other sites

Well your Container on the server can have as much information as you want, as you can make your own subclasses of Container.

 

As for things with the text related field, the server doesn't need to know that it is a GUI at all, it just needs to know that the client has pressed button XYZ. Your best bet would be to setup a communication system between the server and client using the internal messaging system.

You can look at Forge's internal handlers in it's code and this. Not the best in the world, but should be able to point you in the right direction.

 

 

 

I do Forge for free, however the servers to run it arn't free, so anything is appreciated.
Consider supporting the team on Patreon

Link to comment
Share on other sites

Actually, it does seem like I'll have an issue with the ForgeMP GUI setup. Based on the API's and cpw's Iron Chest mod, it seems like to have MP GUIs be handled by Forge I need to call player.openGui. However the parameters sent only work if what the GUI needs is a block coordinate. Many of my GUIs however need to have a reference to the villager the player is interacting with. I suppose I'll have to build my own system for those, using custom packets instead. Also, maybe it's a stupid question, but what is the use of having a container generated server-side for it? Does Forge take care of synching its data with the client?

 

Otherwise I see that to keep tile entities' data synched I need to manually send updates with world.sendClientEvent. What is the equivalent for entities?

Link to comment
Share on other sites

There really sin't an equivalent for entites.

But the reason the server sides uses Containers is because the bulk of Vanilla GUIs do exactly the same thing, they have a slot and you move item stacks around.

All the container code is vanilla minecraft, nothing to do with forge. the openGUI is just a generic interface that deals with signaling the client that it should open a block related GUI, and signing the server that it should expect the client to have a block related GUI open.

 

A couple of modders have hacked around with the openGui function to do some odd stuff, for example, the EnderStorage uses the X value to send the color code of the bag its opening, and ignores the Y/Z.

 

The X/Y/Z are just ints that are transferred intact to the client without manipulation, so you can use them for whatever you want.

I do Forge for free, however the servers to run it arn't free, so anything is appreciated.
Consider supporting the team on Patreon

Link to comment
Share on other sites

There really sin't an equivalent for entites.

 

So what happens when I've created an entity server-side? What infos about it will be sent by the server to the client? And is there a standard way to send extra data?

 

All the container code is vanilla minecraft, nothing to do with forge. the openGUI is just a generic interface that deals with signaling the client that it should open a block related GUI, and signing the server that it should expect the client to have a block related GUI open.

 

I guess what I don't get is why the server would need that. When the player moves a stack from his inventory to a chest for example, how is the info sent back to the server? The GUI code will update the stack on the client I assume, by what mechanism is it synched back?

 

A couple of modders have hacked around with the openGui function to do some odd stuff, for example, the EnderStorage uses the X value to send the color code of the bag its opening, and ignores the Y/Z.

 

The X/Y/Z are just ints that are transferred intact to the client without manipulation, so you can use them for whatever you want.

 

Hmm, I guess that might work for me as well. Bit of a hack but well...

 

Also, just to be sure, methods like Block.blockActivated or Entity.interact are called both client- and server-side, right? Looking at the vanilla code, EntityCow for instance, I find it strange that:

 

par1EntityPlayer.inventory.setInventorySlotContents(par1EntityPlayer.inventory.currentItem, new ItemStack(Item.bucketMilk));

 

is executed both client-side and server-side. Unless the client-side version is only to give immediate feedback to the player, and the server-side one is the only one that matters? So that if for some reason I changed the server-side one to give the player a lava bucket instead, the player would briefly get a milk bucket visible in his inventory due to the client code executing and a second later it would be replaced by a lava one as the server executes its own code and the player's client inventory is overwritten by the server one?

Link to comment
Share on other sites

So what happens when I've created an entity server-side? What infos about it will be sent by the server to the client? And is there a standard way to send extra data?
Look at MinecraftForge.registerEntity, and ISpawnHandler.

I guess what I don't get is why the server would need that. When the player moves a stack from his inventory to a chest for example, how is the info sent back to the server? The GUI code will update the stack on the client I assume, by what mechanism is it synched back?

Take a look at PlayerControllerMP.windowClick, it does all the normal things that clicking on a window does but it also sends to the server, that it clicked the window.

 

Also, just to be sure, methods like Block.blockActivated or Entity.interact are called both client- and server-side, right? Looking at the vanilla code, EntityCow for instance, I find it strange that:

 

par1EntityPlayer.inventory.setInventorySlotContents(par1EntityPlayer.inventory.currentItem, new ItemStack(Item.bucketMilk));

 

is executed both client-side and server-side. Unless the client-side version is only to give immediate feedback to the player, and the server-side one is the only one that matters? So that if for some reason I changed the server-side one to give the player a lava bucket instead, the player would briefly get a milk bucket visible in his inventory due to the client code executing and a second later it would be replaced by a lava one as the server executes its own code and the player's client inventory is overwritten by the server one?

Yup, in this particular case, it edits the inventory, which on the server signifies that it should send the new slot data to the client.

Ever played on a server and gotten your damage values out of sync, had a item in your hand break, but then reappear? This is the exact reason why.

 

However, there are some cases where the code should only be run on one side, and the event is fired on both.

In such cases you should use world.isRemote, to determine if you are the authoritative side of the conversation or not.

Droping items from blocks is an example, When a block drop is created, it checks world.isRemote, if that is true, it doesn't add it to the world.

If it did, the client would see duplicate entities.

I do Forge for free, however the servers to run it arn't free, so anything is appreciated.
Consider supporting the team on Patreon

Link to comment
Share on other sites

Look at MinecraftForge.registerEntity, and ISpawnHandler.

 

Ah, convenient. And I see that the movement values of entities are automatically synched, in EntityTrackerEntry. However there doesn't seem to be a way to keep extra pieces of data synchronised - am I missing something?

 

Take a look at PlayerControllerMP.windowClick, it does all the normal things that clicking on a window does but it also sends to the server, that it clicked the window.

 

Ok... So the whole GUI interaction is emulated server-side in the container class... Let's see if I can use that.

 

Yup, in this particular case, it edits the inventory, which on the server signifies that it should send the new slot data to the client.

Ever played on a server and gotten your damage values out of sync, had a item in your hand break, but then reappear? This is the exact reason why.

 

Yep, all clear now.

Link to comment
Share on other sites

Small question, the signature of onTickInGame() is different on the client and sever (one has a Minecraft parameter, the other a MinecraftServer one). Is this intended? I wanted to keep the same mod_Millenaire class for both sides but I don't see how I can do that and use the method in question.

Link to comment
Share on other sites

Its not possible without using ITickHandler directly, due to the fact that 'Minecraft' doesn't exist on the server.

And 'MinecraftServer' doesn't exist on the client.

This is a design flaw that is in there because of Risugami and us having to be backwards compatible with ModLoader mods.

 

However, after your inital port, I would advise you take a look into ITickHandler it gives you better contorler over many ticks

 

I do Forge for free, however the servers to run it arn't free, so anything is appreciated.
Consider supporting the team on Patreon

Link to comment
Share on other sites

Thanks. I'll look at it now in fact, if it's not too complicated I'd rather use that rather than splitting my mod class. What would be the tick types to use as equivalents to the onTickInGame() and onTickInGUI() methods?

 

Same question for registerAnimation(). Is there an alternative that doesn't cause compile problems?

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




  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • They were already updated, and just to double check I even did a cleanup and fresh update from that same page. I'm quite sure drivers are not the problem here. 
    • i tried downloading the drivers but it says no AMD graphics hardware has been detected    
    • Update your AMD/ATI drivers - get the drivers from their website - do not update via system  
    • As the title says i keep on crashing on forge 1.20.1 even without any mods downloaded, i have the latest drivers (nvidia) and vanilla minecraft works perfectly fine for me logs: https://pastebin.com/5UR01yG9
    • Hello everyone, I'm making this post to seek help for my modded block, It's a special block called FrozenBlock supposed to take the place of an old block, then after a set amount of ticks, it's supposed to revert its Block State, Entity, data... to the old block like this :  The problem I have is that the system breaks when handling multi blocks (I tried some fix but none of them worked) :  The bug I have identified is that the function "setOldBlockFields" in the item's "setFrozenBlock" function gets called once for the 1st block of multiblock getting frozen (as it should), but gets called a second time BEFORE creating the first FrozenBlock with the data of the 1st block, hence giving the same data to the two FrozenBlock :   Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=head] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@73681674 BlockEntityData : id:"minecraft:bed",x:3,y:-60,z:-6} Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=3, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=2, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} here is the code inside my custom "freeze" item :    @Override     public @NotNull InteractionResult useOn(@NotNull UseOnContext pContext) {         if (!pContext.getLevel().isClientSide() && pContext.getHand() == InteractionHand.MAIN_HAND) {             BlockPos blockPos = pContext.getClickedPos();             BlockPos secondBlockPos = getMultiblockPos(blockPos, pContext.getLevel().getBlockState(blockPos));             if (secondBlockPos != null) {                 createFrozenBlock(pContext, secondBlockPos);             }             createFrozenBlock(pContext, blockPos);             return InteractionResult.SUCCESS;         }         return super.useOn(pContext);     }     public static void createFrozenBlock(UseOnContext pContext, BlockPos blockPos) {         BlockState oldState = pContext.getLevel().getBlockState(blockPos);         BlockEntity oldBlockEntity = oldState.hasBlockEntity() ? pContext.getLevel().getBlockEntity(blockPos) : null;         CompoundTag oldBlockEntityData = oldState.hasBlockEntity() ? oldBlockEntity.serializeNBT() : null;         if (oldBlockEntity != null) {             pContext.getLevel().removeBlockEntity(blockPos);         }         BlockState FrozenBlock = setFrozenBlock(oldState, oldBlockEntity, oldBlockEntityData);         pContext.getLevel().setBlockAndUpdate(blockPos, FrozenBlock);     }     public static BlockState setFrozenBlock(BlockState blockState, @Nullable BlockEntity blockEntity, @Nullable CompoundTag blockEntityData) {         BlockState FrozenBlock = BlockRegister.FROZEN_BLOCK.get().defaultBlockState();         ((FrozenBlock) FrozenBlock.getBlock()).setOldBlockFields(blockState, blockEntity, blockEntityData);         return FrozenBlock;     }  
  • Topics

×
×
  • Create New...

Important Information

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