Jump to content

My secret project - Doppelganger, a plugin for PvE.


totemo
 Share

Recommended Posts

dop·pel·gäng·er or dop·pel·gang·er 
n.
A ghostly double of a living person, especially one that haunts its fleshly counterpart.

 
Well, it hasn't been super secret and, for reasons of transparency, the sources are up on github, but I've been keeping it on the down low because I hope that it can be a surprise present for the PvE players and for that reason I hope you'll keep a lid on it too.
 
Around about the time that Survival got player-dropped skulls I decided I wanted a way for PvE players to get them too.  I dreamed up a mechanism similar to how golems are summoned in vanilla Minecraft:

  • Build a stack of blocks in a prescribed shape.
  • Place a final block on top as the head of the creature.

In the case of Doppelganger, since I wanted to be able to get the head of a specific player, I made it a requirement that the head block has to be named on an anvil.  The summoned creature will wear the head of the player with that name.
 
Here's what it looks like in action, placing a named pumpkin on a gold block atop a diamond block to summon a zombie pigman wearing my own head:
 
bsWXcdo.jpgRZKtfwg.jpg

There's a flash of lighting, a wither spawn sound and the gold and diamond blocks are turned into air.  The named pumpkin is removed from the player's inventory.  If I then kill that doppelganger, it will drop my head with the probability specified in the configuration.  If I place that dropped head on another gold/diamond stack, nothing will happen (no creature is summoned, nothing is lost) because it needs to be named on an anvil first.
 
I decided that not all heads are created equal, so I added the ability to have special player names that require a specific shape to summon them.  So for instance, in the example configuration,  Notch and jeb_ both require that you build a more expensive T-shape out of diamond blocks.  If a player tries to summon Notch with some other golem shape, the plugin will tell them "That's not how you summon Notch." and simply go ahead with the placement of the head block as if it had not been named (no creature is summoned, nothing is lost).
 
1LdFpzk.jpgbmSe8Re.jpg

Like any Doppelganger creature, Notch and jeb_ can be configured with a host of "escort" creatures to help them battle the player.  Notch is escorted by "FlyingSkull"s (invisible, fire-resistant skeletons wearing skulls, carrying high powered bows and riding on invisible blazes).  jeb_ is riding a flying pig (courtesy of invisible bats) and then, well, you can see.
 
Of course all of these things are just configuration details.  And none of these things is in the default configuration - that's empty. Here's another illustration of what can be done:
 
9WlU99r.jpg
 
Thrawn21 suggested that buzzie71 might like Doppelgangers in the 6K as "Dr Sign" and his molon-headed minions.  So I implemented a "mask" feature: the creature is named Villain (to be deliberately vague in the example configuration on github), but is wearing Ooer's head as a mask.
 
And some more examples just for fun:

  • Summoning bats, flying pigs and flying squids just by placing named pumpkins.
  • Summoning named villagers with a pumpkin on wool.
  • Summoning named cows with a skull, wool and fence gates.

SAbxM3x.jpg
NEFT1NG.jpg
Fgxmda3.jpg
T3JS0vd.jpg
 
I wrote Doppelganger to be extremely configurable, within the confines of what Bukkit allows you to do with the vanilla game.  You can:

  • Configure the shapes of the piles of blocks, specifying a distinct material for each block and its position relative to the final head block.
    • You can specify what kinds of creatures a particular shape will summon and the probabilities of it summoning each.
    • Whether this shape is enabled or not.  This allows you to have a shape defined in the configuration file but prevent it from being used to summon creatures.
    • You can even define a shape which is just the head block. The example configuration uses pumpkins to illustrate this.
  • Configure the creatures that get summoned.
    • You can specify the base creature type.  It can be just the plain Bukkit LivingEntity name like "bat" or "skeleton", plus a couple of vanilla creatures that Bukkit doesn't have a name for, "witherskeleton" and "saddledpig".
    • Or you can define a new type of creature in terms of any other creature that could be created in the vanilla game (or recursively in terms of any creature you have defined yourself), plus the following customisations:
      • Whether the creature despawns or not.
      • The maximum health of the creature in half-hearts.
      • The lung capacity of the creature in ticks before it will suffocate if deprived of air.
      • The mount - the type of creature that this creature will ride.
      • A block, helmet or skull on its head.
      • The creature's mask: for certain special creatures you can stipulate that they wear the head of a specific player, rather than the name that they were given.  The idea being that I could, for example, summon DrSign, but have the creature wear the head of a player whose skin I like better.
      • The type of armour it wears and what weapon it carries.
      • The individual enchantments and durability on any armour or weapons.
      • The probability of dropping the head/helmet, armor and weapon.
      • Potion buffs, including any that can be applied to mobs, irrespective of whether players can brew them.
      • The sound that gets played when the creature appears.
      • The minimum and maximum number of random, damage-free lighting strikes that hit the ground nearby, and the minimum and maximum range of these from the spawn point of the creature.
  • Define distinguished player names (e.g. Notch, jeb_) that summon specific creatures and require specific (typically more expensive) shapes to be summoned.  Attempts to summon these using cheaper shapes will fail.

There's also a command line interface that can show descriptions of shapes, creature types and player overrides, find doppelgangers by name and show their coordinates, kill doppelgangers by name, spawn named or anonymous creatures of any type and finally a combination of killing and spawning: maintaining a creature in a defined volume. If a maintained creature dies or otherwise does not exist in the specified volume, it is spawned. If more than one creature with the specified name exists in the volume, all but the oldest are killed.

vlIDiI2.jpg

All of these commands have colourful, built-in help (which you can only see if you have permission to use the particular subcommand of /doppel) and are written to be usable by players, from the console and from command blocks. Supported volumes are currently just spheres and boxes.

Some final points:

  • No, it's not exactly vanilla and we are an as-vanilla-as-possible server, but it's quasi-vanila (vanilla-like).
  • I think our players will love this for two reasons:
  • They can get skulls on PvE.
  • It will give them more interesting mob fights.  People are getting somewhat jaded by the level of difficulty on P.  They hold wither fights and stipulate "no armour" and other restrictions to make the fight more challenging.  Doppelganger mobs can be as tough as you like.  The example configuration includes some truly terrifying, fast, strong creatures.
  • The configuration allows admins to impose a cost on obtaining player skulls, in terms of an arbitrary set of base blocks and the named head item.  The cost can be adjusted for specific premium player heads.
  • Because the final placement of the head block does not happen (the event is cancelled), it won't be logged by LogBlock, so the plugin logs all details of successful summoning in the server console (player, shape, creature, creature name, world, coordinates).  (I have an idea to allow the placement and then schedule removal of the blocks immediately that I will look into soon.). If a player was to maliciously summon a creature, either to harm an unconsenting player, or to destroy high-valued blocks, they could be tracked through the server logs.
  • In order to spawn a doppelganger, there must be a one block air gap horizontally on all sides around the bounding box of the body and head together. (An air gap above or below is not required.) That makes it impossible to grief beacons with a shape that consumes diamond blocks or whatnot.
  • It's a pure-Bukkit plugin and should not require recompilation if the servers upgrade (but there's a Maven pom.xml file so recompiling is dead easy).
  • To check whether a doppelganger has been summoned, the plugin hooks the block place event. The code strives to make this as efficient as possible by checking for the least likely requirements first. For example, quite probably, nobody has ever placed an explicitly named block on PvE, and that's the first thing that gets checked. If the block isn't named, the plugin doesn't need to consider the event further.

And to conclude, I made this for us. If you have the authority to make this a part of PvE, please consider doing so.

  • Upvote 3
Link to comment
Share on other sites

totemo,

 

Oh-ho-ho-ho! (devilish laugh)

 

They'll be some/lots of details to work out amongst the padmins for how we want the configuration, but I'm a definite yes for this and look forward to seeing it in action.  If you have time at some point in the near future to discuss/recommend things in mumble, that'd be great.

Link to comment
Share on other sites

Thank you.

 

One thing I forgot to mention: since players won't be able to see the configuration, and should not (necessarily) be given access to the "/doppel info" command (permission doppelganger.info) they won't know what player overrides or summoning shapes have been configured.  Which means that information can be supplied to them in whatever manner is most entertaining, for example: as the outcome of a "quest".

 

Oh, and earlier I discussed with tompreuss the possibility of adding carried items for the mobs that could then be dropped and in the 6k, for example, used as keys.

 

I'm going to extend that concept to them being able to drop written books if I can.  Is that sparking any ideas? buzzie71?

Link to comment
Share on other sites

Can these dopplegangers be made into spawners?

 

With spawners you could get a similar level of customisation, apparently by editing NBT tags.  I've never done it.  In both cases, there are just the few basic vanilla Minecraft "LivingEntity" types involved, and then customisations (items, potions effects, adjustments to attributes like health) are applied.

 

It's an interesting thought though. I'll have to see what controls over spawners the Bukkit API exposes.  There may already be Bukkit plugins that allow that customisation from commands.

 

As currently conceived, Doppelganger can give somewhat similar results to spawners using a redstone timing circuit, a command block, and the /doppel maintain command.  The differences would be:

  1. The maintained mob would have a visible name tag.  
  2. There would be just one mob retained in that volume (e.g. box) passed to the maintain command with that specific name.  Although anonymous escort mobs could be spawned with it and replenished whenever the command block runs /doppel maintain and detects that it is gone (moved away, dead).

The main thrust of this effort was to make a plausible skull game-mechanic accessible to PvE players (without requiring any fancy commands or NBT editing).  The /doppel coords and /doppel kill commands are there for when Doppelgangers get out of hand; /doppel spawn was added for the possibility of staff-run arenas and /doppel maintain for limited use in things like the 6k as boss mob.

 

If command blocks had an actual working Bukkit API for specifying their redstone output I might have simply used /doppel coords, /doppel kill, /doppel spawn and some redstone in-game.

Link to comment
Share on other sites

I added names and lore (multiple custom extra description lines) to items.  If a creature is configured to wear a skull, then whatever custom configuration that skull has is kept when it is turned into a player skull.

 

x81f5II.png

 

 

I don't think that the Bukkit API has a way to set extra items for a creature to drop, apart from the armour and held item (weapon).  For the example configuration, to make Notch drop a special item (a renamed tripwire hook in this case), I made him wear it as his boots.  You can't see him wearing it and it drops just fine.

 

gT8toxl.png

 

For reasons I cannot fathom, even with the drop chance set to 1.0, items occasionally don't drop.  I'm currently experimenting with setting the drop chance to 1.0001 (100.01%) to see if that makes it 100.01% reliable.

Link to comment
Share on other sites

I've mentioned some ideas to tompreuss already (we have also bounced ideas off each other), so in the interests of keeping them secret and appearing to be an evil mastermind, I will not reveal them here.  (Of course I will also proceed to debate the accuracy of me being "evil", but that's beyond the scope of this post.)

 

While typing this and noting the lung capacity above, would it be possible to make the doppelganger a water breather?  Like squids, where they will eventually suffocate and die if out of water for too long?

 

Other than that, this is awesome!  I look forward to seeing this on P...

  • Upvote 1
Link to comment
Share on other sites

While typing this and noting the lung capacity above, would it be possible to make the doppelganger a water breather?  Like squids, where they will eventually suffocate and die if out of water for too long?

 

It could be done.  As far as I'm aware it would require setting up a timer and event handlers to inflict damage on the mob.

 

 

Today I added, an invulnerability duration, so spawned creatures can be invulnerable for a specified number of ticks.  I added customisation of colours in names and lore.  I also added written books.

 

dn73ete.png

 

 

I experimented with the ImgMap plugin, which allows creation of maps with arbitrary image data.

 

It sort of works, but if you drop the item or restart the server, it reverts to the original map.

 

wHEfdVr.pnggcwIwM6.png

62GsgRA.png

Link to comment
Share on other sites

Per discussion with tompreuss this morning, I've added the ability to set the default name of a creature in the configuration.  If the creature is spawned without a name specified (either by command, or because the creature is escorting another creature), then it will take its default name if set.  So if, for example, you want buzzie71 to spawn whenever thrawn21 appears, configure a creature type for both and set the buzzie71 creature as an 'escort' of thrawn21, with minimum number of escorts set to 1.  Beware though, I'm not currently checking for (direct or indirect) mutual-recursion of creatures and their escorts, so if buzzie71 is thrawn21's escort and vice-versa, the plugin will spawn a thrawn21, then a buzzie71 as an escort, then another thrawn21 to escort buzzie71, and so on until the server collapses in a screaming heap.  

 

If you do need escorts to be spawned, either way, you can safely achieve the effect with an extra level of indirection (confirmed by testing):

creatures:

buzzie71_creature:

defaultname: buzzie71

spawn: Skeleton

thrawn21_creature

defaultname: thrawn21

spawn: Skeleton

buzzie71:

spawn: buzzie71_creature

escorts:

min: 1

summon:

- weight: 1.0

  spawn: thrawn21_creature

thrawn21:

spawn: thrawn21_creature
escorts:

min: 1
summon:
- weight: 1.0
  spawn: buzzie71_creature

 

 

In the example configuration, for creature type Notch, I set a default name of Notch, so to spawn a creature with Notch's head by command, you can now just write:

/doppel spawn here Notch

instead of:

/doppel spawn here Notch Notch

 

If a name is specified, or the default name applied, the creature gets a name tag and wears the corresponding player's head.  If a mask has been set, the creature will wear that player's head instead.  (The name tag stays the same.)

 

To allow for a use case where you want escorts to have name tags, but keep whatever head gear was specified as the helmet setting, I added a "keephelmet" attribute of creatures too.  If keephelmet is true, then the creature will wear whatever helmet was configured, irrespective of the name, defaultname, or mask.  In the example configuration, I set default names for both types of Villain's escorts, and set keephelmet to true so that they would still wear melons on their heads:

 

WByaBM0.jpg

Link to comment
Share on other sites

So many customization options...

 

So you're basically writing a Bukkit-compatible plugin that allows any mob, with any name above it, wearing and wielding any item (including customized items), riding any other mob, carrying any effect, having any amount of health, accompanied by any mob/group of mobs automatically, confinable to any area, and summonable in survival by any configuration of blocks imaginable as long as there's a named pumpkin involved.

 

I think there are more possibilities than just getting skulls here.

Link to comment
Share on other sites

summonable in survival by any configuration of blocks imaginable as long as there's a named pumpkin involved.

 

As long as there is a named placeable item involved.  It doesn't have to be a pumpkin.  Some of the example recipes involve placing an actual skull as the head to summon the beast.

Link to comment
Share on other sites

totemo, I'm having a ball testing out stuff so far, and I appreciate all the stuff you've added and helped me with already.

 

Two additional things you may be able to help with:

 

1) I think Villagers just can't wear armor or carry items?  I know I'm assigning them correctly, but I just don't think bukkit allows it since it's not possible in vanilla maybe?  Or am I doing it wrong?

 

2) Is there any way I can define colors to leather armor?  Maybe with org.bukkit.inventory.meta.LeatherArmorMeta or something?

Link to comment
Share on other sites

totemo, I'm having a ball testing out stuff so far, and I appreciate all the stuff you've added and helped me with already.

 

Two additional things you may be able to help with:

 

1) I think Villagers just can't wear armor or carry items?  I know I'm assigning them correctly, but I just don't think bukkit allows it since it's not possible in vanilla maybe?  Or am I doing it wrong?

 

2) Is there any way I can define colors to leather armor?  Maybe with org.bukkit.inventory.meta.LeatherArmorMeta or something?

 

As of yesterday, I have added support for arbitrary RGB (red, green, blue in the range 0 to 255 inclusive) leather colours.  The example configuration has RedSkeleton and BlueSkeleton to demonstrate this.

 

The SpecialVillager type in the configuration is also configured to wear a red leather chestplate, but Bukkit, or more probably the underlying vanilla Minecraft code ignores this.

 

I also added pre-defined types for villager professions: Blacksmith, Butcher, Farmer, Librarian, Priest. For example: /doppel spawn here priest

 

The only other thing I can think of that might be missing at the moment is the ability to request the baby form of mobs, e.g. baby zombies.  I'll add that soon.

 

Denevien filled me in on the context of the desire for armoured villagers.  The only other way I can think of doing it would be to make passive armoured skeletons or zombies.  To make a hostile mob passive, in Bukkit terms, requires the cancellation of the specific EntityTargetEvent raised when the hostile targets a player.  I could add this to Doppelganger, but I'm disinclined to because it adds extra complexity (managing a list of passive creatures, dealing with restarts) and opportunities to go wrong that aren't needed otherwise.

 

I'd be more inclined to put the functionality in a separate plugin that maintains a list of box shaped regions where the event is cancelled.  That would be simple.  But perhaps an even simpler approach in the first instance would be to ask LadyCailin if she would do a CommandHelper script to cancel the target_player event (http://wiki.sk89q.com/wiki/CommandHelper/Staged/Event_API) in a box with hard-wired coordinates that you specify, since it would avoid all of the effort associated with making a full-blown configurable plugin.

Link to comment
Share on other sites

Denevien filled me in on the context of the desire for armoured villagers.  The only other way I can think of doing it would be to make passive armoured skeletons or zombies.  To make a hostile mob passive, in Bukkit terms, requires the cancellation of the specific EntityTargetEvent raised when the hostile targets a player.  I could add this to Doppelganger, but I'm disinclined to because it adds extra complexity (managing a list of passive creatures, dealing with restarts) and opportunities to go wrong that aren't needed otherwise.

 

I'd be more inclined to put the functionality in a separate plugin that maintains a list of box shaped regions where the event is cancelled.  That would be simple.  But perhaps an even simpler approach in the first instance would be to ask LadyCailin if she would do a CommandHelper script to cancel the target_player event (http://wiki.sk89q.com/wiki/CommandHelper/Staged/Event_API) in a box with hard-wired coordinates that you specify, since it would avoid all of the effort associated with making a full-blown configurable plugin.

 

Yeah, I already tested and told Den that we could make zombies that wear armor and have near infinite health that he could trap in a box for their own safety and the safety of the players around them.  Now they will be wearing pretty colored leather armor as well:

 

zxX07ZQl.png

 

Thanks!

 

I heard LadyCailin once say she could code an /easy-sign to do whatever Den wanted in less than 20 minutes.  True story.  If say you put a sign down at the mob's feet that would make a 2x1 box to cancel the target_player event?  Or maybe that's crazy, but I'm sure she could come up with something.

Link to comment
Share on other sites

Yeah, I already tested and told Den that we could make zombies that wear armor and have near infinite health that he could trap in a box for their own safety and the safety of the players around them.  Now they will be wearing pretty colored leather armor as well:

 

 

Or instead of setting infinite health, set "invulnerableticks" to some huge number.  That's the number of ticks that the creature won't take damage after spawning.

 

I forgot to mention that I also added a ZombieVillager predefined type (self-explanatory) and just now I added "baby" (true/false) and "agelocked" (true/false - if true, never grow up) attributes.  The baby and agelocked attributes apply to animals and villagers only.  The Bukkit API is somewhat inconsistent in this regard, since it is also possible to make a baby zombie villager, but not using the same Bukkit API (Ageable).

 

I added another predefined type: BabyZombieVillager.  Unlike animals and villagers, it is not possible (and yes I am using the phrase "not possible" in the conventional programming jargon sense to mean "not fun to do") to prevent this creature from growing up, since it is actually a variation on Zombie.  I added red and blue clad variations to the example configuration:

 

IbdUvEB.jpg

Link to comment
Share on other sites

Added a ChargedCreeper predefined type, which I had forgotten about.  If there are any other types of creatures that can't be spawned with the existing code let me know so that I can add them.

Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...