Jump to content

horsewithnoname

Members
  • Posts

    54
  • Joined

  • Last visited

Everything posted by horsewithnoname

  1. Update 1.1 is out! Change log: – GUIs for director blocks – Improved actor and camera configuration GUIs – Extended place block action (and broke the compatibility with 1.0) – Better camera model (IMO) – Works on dedicated server (fix) Download mod: https://github.com/mchorse/blockbuster/releases/tag/1.1 Tutorial video:
  2. Do you refer to "Multiblock" as the block that consists out of several blocks like bed or door (with health), or as some entity that is made up from blocks (voxel-ish, something like this)?
  3. That's a really nice idea, but I think that the problem of all tutorials are that they aren't going beyond the basics. Most of advanced things I learned either from searching google for my problem and encountering forum topics on minecraftforum.net and minecraftforge.net, or looking up source code of other mods that do what I need to implement (via github for open source mods, and via JD-GUI for closed source mods). I might come back later, when I'll start porting my mod to 1.10, but keep it up anyway!
  4. 1.0 is out! You can download it here: https://github.com/mchorse/blockbuster/releases There's tutorial video: Public release brought to you some of the new features (thanks mostly to Lightwave): 1. Elytra flying 2. /play command invincibility flag
  5. Thank you! By the way, I've just figured out why there was the corruption with the recording code. Basically when I refactored action code, I forgot to override one method. In turn, the whole playback in those places were read wrong, so it was my fault. Right now everything should work as expected. I'm planning to publish video and mod today or tomorrow (but not promising). Edit: uploading video to YouTube, release really soon!
  6. Wow, that's great, means less work. It's totally fine. Hey, I'm amateur too, at least in Minecraft modding, I started one month ago I did a little workaround to enable text formatting in chat while recording chat messages. When you type '[' it would be replaced as '§' and will allow to use minecraft text formatting. You have this problem in log, because, it seems to me, your eclipse doesn't do UTF (when I opened your zip, it had kind of this <?> (used to represent missing representation AFAIK) symbol). Edit: Did some testing on 1.9.4, it's not fully ready, there's some corruption recording code, I'll work on it after release.
  7. I've just added it in the last commit, you can "gradlew build" to get jar with elytra recording. Edit: it's really close to public release 1.0, first I'll publish the demo & tutorial video, and then release.
  8. Sure! Right now I'm working on a overview/tutorial video for my mod, and then I'll start working on support for 1.9.4. By the way, what is difference between 1.9 and 1.9.4? Is it performance mostly or there are some new features? Good idea, I'll add this feature. Done.
  9. Hello there! I'm proud to introduce to you my first published mod, meet Blockbuster mod! Blockbuster will let you capture some basic machinimas (without having to hire/organize crowd of actors and cameras), and create some scripted cinematics (simple yet) for your adventure maps. My mod's player's capturing mod is based on Mocap's source code. Author of this mod gave me permission to use his code. The instruction and all information about the mod is hosted here (I'll create video later): https://github.com/mchorse/blockbuster/blob/master/README.md Download mod jar and adventure map here: https://github.com/mchorse/blockbuster/releases/tag/pre-1.0 I tested my mod on OS X 10.10, but it should work on Windows and *nix too. What do you think? Any issues/errors/crashes with mod? Any suggestions (I have some list of ideas, so there's a lot of room to grow )? Thank you for attention! P.S.: Pun intended.
  10. I solved my problem, and it turned out that the problem wasn't in TE's being replaced. The problem actually was in the wrong storage of block's data. I stored the playing state in block's public boolean field (because I was lazy to write additional code for block's metadata). In the log, there's two messages with two different objects being replaced, but in reality there was two different TE for two different blocks that I didn't noticed. So, the glitch happened because these two TE's were attached to the same block instance with public boolean field. When one of the TE's started playing, the other gets the same value of isPlaying as the initial TE. Basically, now I learned that Block instances are kinda singletons (they're allocated and initiated only once), and now that I understand better Block. The solution was to rewrite block's class to store state in IBlockState, and get this state from TE's instead of directly from the Block's class. [spoiler=Code] public abstract class AbstractDirectorBlock extends Block implements ITileEntityProvider { public static final PropertyBool PLAYING = PropertyBool.create("playing"); /* States */ @Override public int getMetaFromState(IBlockState state) { return state.getValue(PLAYING) ? 1 : 0; } @Override public IBlockState getStateFromMeta(int meta) { return this.getDefaultState().withProperty(PLAYING, meta == 1 ? true : false); } @Override protected BlockStateContainer createBlockState() { return new BlockStateContainer(this, new IProperty[] { PLAYING }); } /* Other code */ } public abstract class AbstractDirectorTileEntity extends TileEntity implements ITickable { /** * Checks every 4 ticks if the actors (that registered by this TE) are * still playing their roles. */ @Override public void update() { if (this.tick-- > 0 || !this.isPlaying()) { return; } this.areActorsStillPlaying(); this.tick = 4; } /** * Does what it says to do – checking if the actors still playing their * roles (not finished playback). */ protected void areActorsStillPlaying() { int count = 0; for (String id : this.actors) { ActorEntity actor = (ActorEntity) Mocap.entityByUUID(this.worldObj, id); if (!Mocap.playbacks.containsKey(actor)) { count++; } } if (count == this.actors.size()) { this.playBlock(false); } } // Using block states instead of Block's public fields /** * Set the state of the block playing (needed to update redstone thingy-stuff) */ protected void playBlock(boolean isPlaying) { this.worldObj.setBlockState(this.pos, this.worldObj.getBlockState(this.pos).withProperty(AbstractDirectorBlock.PLAYING, isPlaying)); } /** * Checks if block's state isPlaying is true */ protected boolean isPlaying() { return this.worldObj.getBlockState(this.pos).getValue(AbstractDirectorBlock.PLAYING); } } Sorry for misleading P.S.: I probably deserve a -1 for misleading
  11. Hello people! I have a problem with tile entities being replaced, which is cause the whole execution to go nuts (because of the local data that not stored on the disk). There's the code: /* Package and Imports */ public class DirectorMapTileEntity extends AbstractDirectorTileEntity { /** * Temporary map of actor entities during playback. This map is used * to determine if the registered actors are still playing their roles. */ protected Map<String, ActorEntity> actorMap = new HashMap<String, ActorEntity>(); @Override public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newSate) { return false; } /** * Add a replay string to list of actors */ public boolean add(String replay) { if (!this.actors.contains(replay)) { this.actors.add(replay); this.markDirty(); return true; } return false; } /** * Starts a playback * * This method is different from the method in DirectorTileEntity, instead * of finding all entities and making them play, this method is basically * do the same thing as CommandPlay#execute, launching the playback * and adding new created entity to actors map. */ @Override public void startPlayback() { if (this.isPlaying()) { return; } for (String replay : this.actors) { String[] splits = replay.split(":"); Entity entity = null; if (splits.length == 2) { entity = Mocap.startPlayback(splits[0], splits[0], splits[1], this.worldObj, true); } else if (splits.length == 1) { entity = Mocap.startPlayback(splits[0], splits[0], splits[0], this.worldObj, true); } this.actorMap.put(replay, (ActorEntity) entity); } this.playBlock(true); } /** * Does what it says to do – checking if the actors still playing their * roles (not finished playback). */ @Override protected void areActorsStillPlaying() { int count = 0; for (String replay : this.actors) { if (Mocap.playbacks.containsKey(this.actorMap.get(replay))) { count++; } } System.out.println(this + " " + this.worldObj.isRemote); if (count == 0) { this.playBlock(false); this.actorMap.clear(); } } } Basically, this TE is responsible for checking if actor entities are still playing and when they'll finish playing to shutdown the operation, basically to switch block's state and switch direction of redstone circuit. As you can see from the code and the log below, when areActorsStillPlaying is called first, everything is ok, but on the next call it's being replaced (I make this assumption based on the class's address change). The local hash map in this TE is really important, but I don't understand why it's being replaced... I tried to return false in shouldRefresh() to avoid replacing of this TE, but it didn't worked. There's the log: How to fix that behavior? Thank you for attention! Edit: is there possibility that it's happens because my actor entities are like 80 blocks away? Because those actor entities in playback can be located really far.
  12. I didn't realized that, thanks for help! Now it works correctly.
  13. Hello guys! I have encountered really weird behavior of processInteract: in forge's development environment processInteract method is triggered twice for some reason, while in regular minecraft version with forge installed sometimes it's either triggered twice or only once. There's the all related code for processInteract: /* Package and imports */ public class ActorEntity extends EntityCreature implements IEntityAdditionalSpawnData { /** * Nasty workaround for processInteract double trigger. */ private int tick = 0; /** * Process interact * * Inject UUID of actor to registering device, open GUI for changing * actor's skin, or start recording him */ @Override protected boolean processInteract(EntityPlayer player, EnumHand p_184645_2_, ItemStack stack) { ItemStack item = player.getHeldItemMainhand(); System.out.println(item + " " + this.worldObj.isRemote); if (item != null && (this.handleRegisterItem(item) || this.handleSkinItem(item, player))) {} else { if (this.tick-- > 0) { return false; } if (!this.worldObj.isRemote) this.startRecording(player); this.tick = 1; } return false; } /** * Set actor's id on register item (while using register item on this * actor) */ private boolean handleRegisterItem(ItemStack stack) { if (this.worldObj.isRemote || !(stack.getItem() instanceof RegisterItem)) { return false; } RegisterItem item = (RegisterItem) stack.getItem(); item.registerStack(stack, this); return true; } /** * Open skin choosing GUI by using skin managing item */ private boolean handleSkinItem(ItemStack stack, EntityPlayer player) { if (!this.worldObj.isRemote || !(stack.getItem() instanceof SkinManagerItem)) { return false; } player.openGui(Blockbuster.instance, 1, this.worldObj, this.getEntityId(), 0, 0); return true; } } And the log: Look for the STDOUT, it's triggered twice on client and server. I don't understand why it's being triggered twice. If it's triggered once when playing on regular minecraft version, players will have to right click entities twice, which is annoying, and that happens sometimes. Does somebody know how to solve this problem? Thank you for attention!
  14. Are you performing these operations (setting new motion) on server, on client, or on both? I encountered similar problem, try moving this logic (setting motion) on server.
  15. I think it would be overkill to make skins via internet for my mod. All I want to do is simply add ability to change skins (plainly putting .png files in the config folder). If I'll implement it via internet, then I'll have to write a website (that would allow users to upload their skins) and REST API (for browsing and downloading skins). That's seems like overkill to me, but it also will add complexity to mod usage (as you'll have to upload skin first, and then find it in the game via GUI). It will only make sense if I'll implement it for some other existent service like skindex. Hm, good idea, I'll look into that.
  16. Hello there! I'm making a mod that allows people to customize player-like entities. I want them to be able to pick a skin (like players format skin) from my mod's config directory. Also I want the skins to be animated (cycle through the skins something like obfuscated text in minecraft). One thing I noticed about texture "loading" for entities is that you can only use ResourceLocation instances to point out where the texture is located via Render#getEntityTexture or so. Which is reduces the scope of textures location only to current classpath (currently loaded jars). So, the question is: How can I load texture using absolute path? Or is it even possible with minecraft's architecture? Thank you for attention!
  17. It supposed to be RenderTest.class instead of RenderTest::new Edit: you actually suppose to create a IRenderFactory implementation for your class
  18. Thanks to Ernio who helped me to overcome this problem, so there's report: To create a GUI that changes state of the custom entity you have to: 1. Create a GUI class that extends GuiScreen (look at GuiCommandBlock for example for click) 2. In your entity's processInteract method on client side (world.isRemote == true) open Gui either via openGui (but first setup IGuiHandler) or via Minecraft.getMinecraft().displayGuiScreen 3. On Gui exit (when you trigger mc.displayGuiScreen(null)), send the message with new values to server side via SimpleNetworkWrapper (as in my second post, see GuiCamera#saveAndExit) 4. On server side in message handler (see CameraAttributesUpdate.Handler#onMessage), you invoke a setter (see Ernio's post where he shows his SNW#updateTracker) which in turn sends another message via your SimpleNetworkWrapper's wrapper to the client 5. On client side you should have another message handler that updates the client entity There's updated SNW#updateTrackers of Ernio: public static void updateTrackers(Entity entity, IMessage message) { EntityTracker et = ((WorldServer) entity.worldObj).getEntityTracker(); for (EntityPlayer player : et.getTrackingPlayers(entity)) { DISPATCHER.sendTo(message, (EntityPlayerMP) player); } } I hope this gonna be helpful in the future P.S.: See also Ernio's links and suggestions for more information
  19. Thanks for another reply! Sorry to disappoint you, but my problem isn't about knowledge of the language. Java is just like any other languages with built-in support of OOP. My problem is that I'm not familiar with minecraft's API. I started developing my mod a week and a half ago. So, now about the EntityTracker. I tried to copy-paste your code examples, but it doesn't seem to work. When I open GUI again it shows the old values in GUI, but on server it prints the sent values. I don't really understand how does SNW#getPacketFrom(message) can magically convert my message into right ordered packet and then on the client side inject those values into correct fields. I read some Forge and Minecraft source code, and now I think I get how to use EntityTracker. From forge.fml.common.registry.EntityRegistry I get that Forge is automatically adds entity to tracking when I register my custom mod, but it seems to me that EntityTracker isn't going to help me with syncing my custom fields from server to the client. EntityTrackerEntry in net.minecraft.entity have a lot of fields, but it looks like it syncing only entity position and rotation. Is that right? Is EntityTracker is responsible only for syncing entity's position and rotation? If so, I can't use EntityTracker to sync my custom data. Correct me if I'm wrong. Also, I decided to add writeEntityToNBT and corresponding reading method to my CameraEntity, and it looks like those custom fields are ok on the server side, but on client side, they're always equals to default, even if I save and quit and then relog again. What am I doing wrong? Fixed by implementing IEntityAdditionSpawnData, but it still doesn't sync while I'm online. This is how my Message looks like now: public class CameraAttributesUpdate implements IMessage { protected int id; protected float speed; protected float accelerationRate; protected float accelerationMax; protected boolean canFly; public CameraAttributesUpdate() {} public CameraAttributesUpdate(int eid, float speeed, float rate, float max, boolean fly) { id = eid; speed = speeed; accelerationRate = rate; accelerationMax = max; canFly = fly; } @Override public void fromBytes(ByteBuf buf) { id = buf.readInt(); speed = buf.readFloat(); accelerationRate = buf.readFloat(); accelerationMax = buf.readFloat(); canFly = buf.readBoolean(); } @Override public void toBytes(ByteBuf buf) { buf.writeInt(id); buf.writeFloat(speed); buf.writeFloat(accelerationRate); buf.writeFloat(accelerationMax); buf.writeBoolean(canFly); } public static class Handler implements IMessageHandler<CameraAttributesUpdate, IMessage> { @Override public IMessage onMessage(final CameraAttributesUpdate message, final MessageContext ctx) { IThreadListener world = (WorldServer)ctx.getServerHandler().playerEntity.worldObj; world.addScheduledTask(new Runnable() { @Override public void run() { WorldServer world = (WorldServer)ctx.getServerHandler().playerEntity.worldObj; Entity entity = world.getEntityByID(message.id); CameraEntity camera = (CameraEntity)entity; camera.setConfiguration(message.speed, message.accelerationRate, message.accelerationMax, message.canFly); world.getEntityTracker().func_151248_b(camera, Mod.channel.getPacketFrom(message)); } }); return null; } } } By the way, my mod is targeted towards single-player experience, so I don't really need to do all those validation checks. P.S.: Sorry if I'm being ignorant, but I just not familiar enough with minecraft and forge code base.
  20. Thanks for another reply! Sorry to disappoint you, but my problem isn't about knowledge of the language. Java is just like any other languages with built-in support of OOP. My problem is that I'm not familiar with minecraft's API. I started developing my mod a week and a half ago. So, now about the EntityTracker. I read some Forge and Minecraft source code, and now I think I get how to use EntityTracker. From forge.fml.common.registry.EntityRegistry I get that Forge is automatically adds entity to tracking when I register my custom mod, but it seems to me that EntityTracker isn't going to help me with syncing my custom fields from server to the client. EntityTrackerEntry By the way, my mod is targeted towards single-player experience, so I don't really need to do all those validation checks.
  21. Thanks, Ernio, for links and suggestions. There's only one problem left to be solved and that's the entity tracking. I don't understand how to use EntityTracker. Is it supposed to be activated on client, on server or on both sides (like in CameraEntity's constructor)? Here's what I've come up with: /* Package and imports */ public class GuiCamera extends GuiScreen { protected GuiSlider speed; protected GuiSlider accelerationRate; protected GuiSlider accelerationMax; protected GuiButton canFly; protected GuiButton done; private CameraEntity camera; public GuiCamera(CameraEntity entity) { camera = entity; } /* initialize GUI */ @Override protected void actionPerformed(GuiButton button) throws IOException { switch (button.id) { case 3: updateFlyButton(); break; case 4: saveAndExit(); break; } } private void saveAndExit() { float cSpeed = (float)speed.getValue(); float cRate = (float)accelerationRate.getValue(); float cMax = (float)accelerationMax.getValue(); boolean cCanFly = canFly.displayString == "Can fly"; Mod.channel.sendToServer(new CameraAttributesUpdate(camera.getEntityId(), cSpeed, cRate, cMax, cCanFly)); camera.speed = cSpeed; camera.accelerationRate = cRate; camera.accelerationMax = cMax; camera.canFly = cCanFly; mc.displayGuiScreen(null); } /* Drawing and clicking logic */ } As you can see I setup SimpleNetworkWrapper and sending message to handle by handler it (on server). This way camera is only synchronized only on client that sent the message and on server, but how to do it to all other connected players? Here's my IMessage and IMessageHandler implementing classes: /* Package and imports */ public class CameraAttributesUpdate implements IMessage { protected int id; protected float speed; protected float accelerationRate; protected float accelerationMax; protected boolean canFly; public CameraAttributesUpdate() {} public CameraAttributesUpdate(int eid, float speeed, float rate, float max, boolean fly) { id = eid; speed = speeed; accelerationRate = rate; accelerationMax = max; canFly = fly; } @Override public void fromBytes(ByteBuf buf) { id = buf.readInt(); speed = buf.readFloat(); accelerationRate = buf.readFloat(); accelerationMax = buf.readFloat(); canFly = buf.readBoolean(); } @Override public void toBytes(ByteBuf buf) { buf.writeInt(id); buf.writeFloat(speed); buf.writeFloat(accelerationRate); buf.writeFloat(accelerationMax); buf.writeBoolean(canFly); } public static class Handler implements IMessageHandler<CameraAttributesUpdate, IMessage> { @Override public IMessage onMessage(final CameraAttributesUpdate message, final MessageContext ctx) { IThreadListener world = (WorldServer)ctx.getServerHandler().playerEntity.worldObj; world.addScheduledTask(new Runnable() { @Override public void run() { Entity entity = ctx.getServerHandler().playerEntity.worldObj.getEntityByID(message.id); CameraEntity camera = (CameraEntity)entity; camera.speed = (float)message.speed; camera.accelerationRate = (float)message.accelerationRate; camera.accelerationMax = (float)message.accelerationMax; camera.canFly = message.canFly; } }); return null; } } } Maybe I can return another message from CameraAttributesUpdate.Handler that will notify somehow other (and maybe the client that sent the message) players?
  22. Thanks, Ernio, for links and suggestions. There's only one problem left to be solved and that's the entity tracking. I don't understand how to use EntityTracker. Is it supposed to be activated on client, on server or on both sides (like in CameraEntity's constructor)? Here's what I've come up with: /* Package and imports */ public class GuiCamera extends GuiScreen { protected GuiSlider speed; protected GuiSlider accelerationRate; protected GuiSlider accelerationMax; protected GuiButton canFly; protected GuiButton done; private CameraEntity camera; public GuiCamera(CameraEntity entity) { camera = entity; } /* initialize GUI */ @Override protected void actionPerformed(GuiButton button) throws IOException { switch (button.id) { case 3: updateFlyButton(); break; case 4: saveAndExit(); break; } } private void saveAndExit() { float cSpeed = (float)speed.getValue(); float cRate = (float)accelerationRate.getValue(); float cMax = (float)accelerationMax.getValue(); boolean cCanFly = canFly.displayString == "Can fly"; Mod.channel.sendToServer(new CameraAttributesUpdate(camera.getEntityId(), cSpeed, cRate, cMax, cCanFly)); camera.speed = cSpeed; camera.accelerationRate = cRate; camera.accelerationMax = cMax; camera.canFly = cCanFly; mc.displayGuiScreen(null); } /* Drawing and clicking logic */ } As you can see I setup SimpleNetworkWrapper and sending message to handle by handler it (on server). This way camera is only synchronized only on client that sent the message and on server, but how to do it to all other connected players? Here's my IMessage and IMessageHandler implementing classes: /* Package and imports */ public class CameraAttributesUpdate implements IMessage { protected int id; protected float speed; protected float accelerationRate; protected float accelerationMax; protected boolean canFly; public CameraAttributesUpdate() {} public CameraAttributesUpdate(int eid, float speeed, float rate, float max, boolean fly) { id = eid; speed = speeed; accelerationRate = rate; accelerationMax = max; canFly = fly; } @Override public void fromBytes(ByteBuf buf) { id = buf.readInt(); speed = buf.readFloat(); accelerationRate = buf.readFloat(); accelerationMax = buf.readFloat(); canFly = buf.readBoolean(); } @Override public void toBytes(ByteBuf buf) { buf.writeInt(id); buf.writeFloat(speed); buf.writeFloat(accelerationRate); buf.writeFloat(accelerationMax); buf.writeBoolean(canFly); } public static class Handler implements IMessageHandler<CameraAttributesUpdate, IMessage> { @Override public IMessage onMessage(final CameraAttributesUpdate message, final MessageContext ctx) { IThreadListener world = (WorldServer)ctx.getServerHandler().playerEntity.worldObj; world.addScheduledTask(new Runnable() { @Override public void run() { Entity entity = ctx.getServerHandler().playerEntity.worldObj.getEntityByID(message.id); CameraEntity camera = (CameraEntity)entity; camera.speed = (float)message.speed; camera.accelerationRate = (float)message.accelerationRate; camera.accelerationMax = (float)message.accelerationMax; camera.canFly = message.canFly; } }); return null; } } } Maybe I can return another message from CameraAttributesUpdate.Handler that will notify somehow other (and maybe the client that sent the message) players?
×
×
  • Create New...

Important Information

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