Add faction votes

This commit is contained in:
Magnus Ulf 2019-01-19 19:27:54 +01:00
parent 1157607397
commit 7171d43a2a
19 changed files with 573 additions and 6 deletions

View File

@ -113,6 +113,12 @@ permissions:
factions.unclaim.square: {description: unclaim by square and radius, default: false}
factions.unclaim.circle: {description: unclaim by circle and radius, default: false}
factions.unclaim.all: {description: unclaim all faction land, default: false}
factions.vote: {description: vote in faction votes, default: false}
factions.vote.do: {description: do vote, default: false}
factions.vote.list: {description: list votes, default: false}
factions.vote.show: {description: show vote result, default: false}
factions.vote.create: {description: create a vote, default: false}
factions.vote.remove: {description: remove a vote, default: false}
factions.warp: {description: use warps, default: false}
factions.warp.go: {description: go to a warp, default: false}
factions.warp.list: {description: list warps, default: false}
@ -239,6 +245,12 @@ permissions:
factions.unclaim.all: true
factions.unsethome: true
factions.unstuck: true
factions.vote: true
factions.vote.do: true
factions.vote.list: true
factions.vote.show: true
factions.vote.create: true
factions.vote.remove: true
factions.warp: true
factions.warp.go: true
factions.warp.list: true
@ -384,6 +396,12 @@ permissions:
factions.unclaim.all: true
factions.unsethome: true
factions.unstuck: true
factions.vote: true
factions.vote.do: true
factions.vote.list: true
factions.vote.show: true
factions.vote.create: true
factions.vote.remove: true
factions.warp: true
factions.warp.go: true
factions.warp.list: true

View File

@ -1,11 +1,9 @@
package com.massivecraft.factions.cmd;
import com.massivecraft.factions.Factions;
import com.massivecraft.factions.Perm;
import com.massivecraft.factions.entity.MConf;
import com.massivecraft.massivecore.command.MassiveCommandDeprecated;
import com.massivecraft.massivecore.command.MassiveCommandVersion;
import com.massivecraft.massivecore.command.requirement.RequirementHasPerm;
import java.util.List;
@ -30,6 +28,7 @@ public class CmdFactions extends FactionsCommand
public CmdFactionsJoin cmdFactionsJoin = new CmdFactionsJoin();
public CmdFactionsLeave cmdFactionsLeave = new CmdFactionsLeave();
public CmdFactionsWarp cmdFactionsWarp = new CmdFactionsWarp();
public CmdFactionsVote cmdFactionsVote = new CmdFactionsVote();
public CmdFactionsMap cmdFactionsMap = new CmdFactionsMap();
public CmdFactionsCreate cmdFactionsCreate = new CmdFactionsCreate();
public CmdFactionsName cmdFactionsName = new CmdFactionsName();

View File

@ -0,0 +1,15 @@
package com.massivecraft.factions.cmd;
public class CmdFactionsVote extends FactionsCommand
{
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
public CmdFactionsVoteShow cmdFactionsVoteShow = new CmdFactionsVoteShow();
public CmdFactionsVoteList cmdFactionsVoteList = new CmdFactionsVoteList();
public CmdFactionsVoteDo cmdFactionsVoteDo = new CmdFactionsVoteDo();
public CmdFactionsVoteCreate cmdFactionsVoteCreate = new CmdFactionsVoteCreate();
public CmdFactionsVoteRemove cmdFactionsVoteRemove = new CmdFactionsVoteRemove();
}

View File

@ -0,0 +1,71 @@
package com.massivecraft.factions.cmd;
import com.massivecraft.factions.entity.MPerm;
import com.massivecraft.factions.entity.Vote;
import com.massivecraft.factions.event.EventFactionsVoteAdd;
import com.massivecraft.massivecore.MassiveException;
import com.massivecraft.massivecore.collections.MassiveList;
import com.massivecraft.massivecore.command.type.container.TypeList;
import com.massivecraft.massivecore.command.type.primitive.TypeString;
import com.massivecraft.massivecore.util.IdUtil;
import java.util.List;
public class CmdFactionsVoteCreate extends FactionsCommandWarp
{
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public CmdFactionsVoteCreate()
{
// Parameters
this.addParameter(TypeString.get(), "name");
this.addParameter(TypeList.get(TypeString.get()), "options", true);
}
// -------------------------------------------- //
// OVERRIDE
// -------------------------------------------- //
@Override
public void perform() throws MassiveException
{
// Args
String name = this.readArg();
List<String> options = this.readArg();
// MPerm
if ( ! MPerm.getPermCreateVote().has(msender, msenderFaction, true)) return;
if (msenderFaction.getVoteByName(name).isPresent())
{
throw new MassiveException().addMsg("<b>There is already a vote called <h>%s<b>.", name);
}
// Make sure there are no duplicated
List<String> options2 = new MassiveList<>();
for (String str : options)
{
if (options2.stream().anyMatch(str::equalsIgnoreCase)) continue;
options2.add(str);
}
Vote vote = new Vote(IdUtil.getId(sender), name, options2);
// Event
EventFactionsVoteAdd event = new EventFactionsVoteAdd(sender, msenderFaction, vote);
event.run();
if (event.isCancelled()) return;
vote = event.getVote();
// Apply
msenderFaction.addVote(vote);
// Inform
msenderFaction.msg("%s<i> added the vote <h>%s <i>to your faction. You can now use:", msender.describeTo(msenderFaction, true), vote.getName());
msenderFaction.sendMessage(CmdFactions.get().cmdFactionsVote.cmdFactionsVoteDo.getTemplateWithArgs(null, vote.getName()));
}
}

View File

@ -0,0 +1,46 @@
package com.massivecraft.factions.cmd;
import com.massivecraft.factions.cmd.type.TypeVote;
import com.massivecraft.factions.entity.MPerm;
import com.massivecraft.factions.entity.Vote;
import com.massivecraft.massivecore.MassiveException;
import com.massivecraft.massivecore.command.type.primitive.TypeString;
public class CmdFactionsVoteDo extends FactionsCommandWarp
{
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public CmdFactionsVoteDo()
{
// Parameters
this.addParameter(TypeVote.get());
this.addParameter(TypeString.get(), "option");
}
// -------------------------------------------- //
// OVERRIDE
// -------------------------------------------- //
@Override
public void perform() throws MassiveException
{
// Args
Vote vote = TypeVote.get(msenderFaction).read(this.arg(), sender);
String option = this.readArg();
// Any and MPerm
if ( ! MPerm.getPermVote().has(msender, msenderFaction, true)) return;
if (vote.getOptions().stream().noneMatch(option::equalsIgnoreCase))
{
throw new MassiveException().addMsg("<b>No option in <h>%s <b>matches <h>%s<b>.", vote.getName(), option);
}
vote.setVote(msender, option);
msg("<i>Succesfully voted for <h>%s <i>in <h>%s<i>.", option, vote.getName());
}
}

View File

@ -0,0 +1,42 @@
package com.massivecraft.factions.cmd;
import com.massivecraft.factions.entity.Vote;
import com.massivecraft.massivecore.MassiveException;
import com.massivecraft.massivecore.command.Parameter;
import com.massivecraft.massivecore.pager.Pager;
import com.massivecraft.massivecore.pager.Stringifier;
import com.massivecraft.massivecore.util.Txt;
public class CmdFactionsVoteList extends FactionsCommandWarp
{
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public CmdFactionsVoteList()
{
// Parameters
this.addParameter(Parameter.getPage());
}
// -------------------------------------------- //
// OVERRIDE
// -------------------------------------------- //
@Override
public void perform() throws MassiveException
{
// Args
int idx = this.readArg();
Pager<Vote> pager = new Pager<>(this, "Faction Votes", idx, msenderFaction.getVotes().getAll());
pager.setMsonifier((Stringifier<Vote>) (vote, i) ->
{
String options = Txt.implodeCommaAndDot(vote.getOptions(), Txt.parse("<teal>%s"), Txt.parse("<i>, "), Txt.parse(" <i>and "), "");
return Txt.parse("<lime>%s<i>: %s", vote.getName(), options);
});
pager.message();
}
}

View File

@ -0,0 +1,47 @@
package com.massivecraft.factions.cmd;
import com.massivecraft.factions.cmd.type.TypeVote;
import com.massivecraft.factions.entity.MPerm;
import com.massivecraft.factions.entity.Vote;
import com.massivecraft.factions.event.EventFactionsVoteRemove;
import com.massivecraft.massivecore.MassiveException;
public class CmdFactionsVoteRemove extends FactionsCommandWarp
{
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public CmdFactionsVoteRemove()
{
// Parameters
this.addParameter(TypeVote.get(), "vote");
}
// -------------------------------------------- //
// OVERRIDE
// -------------------------------------------- //
@Override
public void perform() throws MassiveException
{
// Args
Vote vote = TypeVote.get(msenderFaction).read(this.arg(), sender);
// Any and MPerm
if ( ! MPerm.getPermCreateVote().has(msender, msenderFaction, true)) return;
// Event
EventFactionsVoteRemove event = new EventFactionsVoteRemove(sender, msenderFaction, vote);
event.run();
if (event.isCancelled()) return;
vote = event.getVote();
// Apply
vote.detach();
// Inform
msender.msg("%s<i> removed the vote <h>%s <i>from your faction.", msender.describeTo(msenderFaction, true), vote.getName());
}
}

View File

@ -0,0 +1,49 @@
package com.massivecraft.factions.cmd;
import com.massivecraft.factions.cmd.type.TypeVote;
import com.massivecraft.factions.entity.Vote;
import com.massivecraft.massivecore.MassiveException;
import com.massivecraft.massivecore.util.Txt;
public class CmdFactionsVoteShow extends FactionsCommandWarp
{
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public CmdFactionsVoteShow()
{
// Parameters
this.addParameter(TypeVote.get());
}
// -------------------------------------------- //
// OVERRIDE
// -------------------------------------------- //
@Override
public void perform() throws MassiveException
{
// Args
Vote vote = TypeVote.get(msenderFaction).read(this.arg(), sender);
// Clean the vote
vote.clean();
// Message
message(Txt.titleize("Votes for " + vote.getName()));
int numberOfVotes = vote.getId2Vote().size();
for (String option : vote.getOptions())
{
long num = vote.getId2Vote().values().stream()
.filter(option::equalsIgnoreCase).count();
double percent = ((double) num / (double) numberOfVotes) * 100;
if (Double.isInfinite(percent)) percent = 0D;
String str = Txt.parse("<lime>%s<i>: <i>%d/%d (<h>%.2f%%<i>)", option, num, numberOfVotes, percent);
message(str);
}
}
}

View File

@ -39,6 +39,7 @@ public class CmdFactionsWarpRemove extends FactionsCommandWarp
EventFactionsWarpRemove event = new EventFactionsWarpRemove(sender, faction, warp);
event.run();
if (event.isCancelled()) return;
warp = event.getWarp();
// Apply
warp.detach();

View File

@ -11,6 +11,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Set;
public abstract class TypeEntityInternalFaction<E extends EntityInternal<E>> extends TypeAbstractChoice<E>
{
// -------------------------------------------- //

View File

@ -8,6 +8,7 @@ import org.bukkit.command.CommandSender;
import java.util.Collection;
import java.util.List;
import java.util.Set;
public class TypeRank extends TypeEntityInternalFaction<Rank>
@ -43,6 +44,7 @@ public class TypeRank extends TypeEntityInternalFaction<Rank>
private final Rank currentRank;
// -------------------------------------------- //
// OVERRIDE
// -------------------------------------------- //

View File

@ -0,0 +1,37 @@
package com.massivecraft.factions.cmd.type;
import com.massivecraft.factions.entity.Faction;
import com.massivecraft.factions.entity.Vote;
import java.util.Collection;
public class TypeVote extends TypeEntityInternalFaction<Vote>
{
// -------------------------------------------- //
// INSTANCE & CONSTRUCT
// -------------------------------------------- //
private static TypeVote i = new TypeVote();
public static TypeVote get() { return i; }
private TypeVote()
{
super(Vote.class);
}
public static TypeVote get(Faction faction) { return new TypeVote(faction); }
public TypeVote(Faction faction)
{
super(Vote.class, faction);
}
// -------------------------------------------- //
// OVERRIDE
// -------------------------------------------- //
@Override
public Collection<Vote> getAll(Faction faction)
{
return faction.getVotes().getAll();
}
}

View File

@ -77,6 +77,7 @@ public class Faction extends Entity<Faction> implements FactionsParticipator, MP
this.setPowerBoost(that.powerBoost);
this.invitations.load(that.invitations);
this.ranks.load(that.ranks);
this.votes.load(that.votes);
this.setRelationWishes(that.relationWishes);
this.setFlagIds(that.flags);
this.perms = that.perms;
@ -143,12 +144,14 @@ public class Faction extends Entity<Faction> implements FactionsParticipator, MP
// This is the ids of the invited players.
// They are actually "senderIds" since you can invite "@console" to your faction.
// Null means no one is invited
private EntityInternalMap<Invitation> invitations = new EntityInternalMap<>(this, Invitation.class);
// This is where all the ranks are, they are faction specific
private EntityInternalMap<Rank> ranks = this.createRankMap();
// This is the votes currently open in the faction
private EntityInternalMap<Vote> votes = new EntityInternalMap<>(this, Vote.class);
// The keys in this map are factionIds.
// Null means no special relation whishes.
private MassiveMapDef<String, Rel> relationWishes = new MassiveMapDef<>();
@ -569,6 +572,26 @@ public class Faction extends Entity<Faction> implements FactionsParticipator, MP
return ret;
}
// -------------------------------------------- //
// FIELD: votes
// -------------------------------------------- //
// RAW
public EntityInternalMap<Vote> getVotes() { return this.votes; }
public void addVote(Vote vote)
{
if (vote == null) throw new NullPointerException("vote");
this.getVotes().attach(vote);
}
public Optional<Vote> getVoteByName(String name)
{
if (name == null) throw new NullPointerException("name");
return this.getVotes().getAll().stream().filter(vote -> vote.getName().equalsIgnoreCase(name)).findFirst();
}
// -------------------------------------------- //
// FIELD: relationWish
// -------------------------------------------- //

View File

@ -52,6 +52,8 @@ public class MPerm extends Entity<MPerm> implements Prioritized, Registerable, N
public final static transient String ID_WITHDRAW = "withdraw";
public final static transient String ID_TERRITORY = "territory";
public final static transient String ID_ACCESS = "access";
public final static transient String ID_VOTE = "VOTE";
public final static transient String ID_CREATEVOTE = "createvote";
public final static transient String ID_CLAIMNEAR = "claimnear";
public final static transient String ID_REL = "rel";
public final static transient String ID_DISBAND = "disband";
@ -78,6 +80,8 @@ public class MPerm extends Entity<MPerm> implements Prioritized, Registerable, N
public final static transient int PRIORITY_WITHDRAW = 16000;
public final static transient int PRIORITY_TERRITORY = 17000;
public final static transient int PRIORITY_ACCESS = 18000;
public final static transient int PRIORITY_VOTE = 18200;
public final static transient int PRIORITY_CREATEVOTE = 18600;
public final static transient int PRIORITY_CLAIMNEAR = 19000;
public final static transient int PRIORITY_REL = 20000;
public final static transient int PRIORITY_DISBAND = 21000;
@ -128,6 +132,8 @@ public class MPerm extends Entity<MPerm> implements Prioritized, Registerable, N
getPermWithdraw();
getPermTerritory();
getPermAccess();
getPermVote();
getPermCreateVote();
getPermClaimnear();
getPermRel();
getPermDisband();
@ -155,6 +161,8 @@ public class MPerm extends Entity<MPerm> implements Prioritized, Registerable, N
public static MPerm getPermWithdraw() { return getCreative(PRIORITY_WITHDRAW, ID_WITHDRAW, ID_WITHDRAW, "withdraw money", MUtil.set("LEADER"), false, true, true); }
public static MPerm getPermTerritory() { return getCreative(PRIORITY_TERRITORY, ID_TERRITORY, ID_TERRITORY, "claim or unclaim", MUtil.set("LEADER", "OFFICER"), false, true, true); }
public static MPerm getPermAccess() { return getCreative(PRIORITY_ACCESS, ID_ACCESS, ID_ACCESS, "grant territory", MUtil.set("LEADER", "OFFICER"), false, true, true); }
public static MPerm getPermVote() { return getCreative(PRIORITY_VOTE, ID_VOTE, ID_VOTE, "vote", MUtil.set("LEADER", "OFFICER", "MEMBER", "RECRUIT"), false, true, true); }
public static MPerm getPermCreateVote() { return getCreative(PRIORITY_CREATEVOTE, ID_CREATEVOTE, ID_CREATEVOTE, "manage votes", MUtil.set("LEADER", "OFFICER"), false, true, true); }
public static MPerm getPermClaimnear() { return getCreative(PRIORITY_CLAIMNEAR, ID_CLAIMNEAR, ID_CLAIMNEAR, "claim nearby", MUtil.set("LEADER", "OFFICER", "MEMBER", "RECRUIT", "ALLY"), false, false, false); } // non editable, non visible.
public static MPerm getPermRel() { return getCreative(PRIORITY_REL, ID_REL, ID_REL, "change relations", MUtil.set("LEADER", "OFFICER"), false, true, true); }
public static MPerm getPermDisband() { return getCreative(PRIORITY_DISBAND, ID_DISBAND, ID_DISBAND, "disband the faction", MUtil.set("LEADER"), false, true, true); }
@ -203,6 +211,7 @@ public class MPerm extends Entity<MPerm> implements Prioritized, Registerable, N
private transient boolean registered = false;
public boolean isRegistered() { return this.registered; }
public void setRegistered(boolean registered) { this.registered = registered; }
// -------------------------------------------- //
// VERSION
// -------------------------------------------- //

View File

@ -0,0 +1,127 @@
package com.massivecraft.factions.entity;
import com.massivecraft.massivecore.Named;
import com.massivecraft.massivecore.collections.MassiveMap;
import com.massivecraft.massivecore.store.EntityInternal;
import com.massivecraft.massivecore.store.EntityInternalMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class Vote extends EntityInternal<Vote> implements Named
{
// -------------------------------------------- //
// OVERRIDE: ENTITY
// -------------------------------------------- //
@Override
public Vote load(Vote that)
{
this.creatorId = that.creatorId;
this.creationMillis = that.creationMillis;
this.options = that.options;
this.id2Vote = that.id2Vote;
return this;
}
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
private String creatorId;
public String getCreatorId() { return this.creatorId; }
private long creationMillis;
public long getCreationMillis() { return this.creationMillis; }
private String name;
@Override public String getName() { return this.name; }
private List<String> options;
public List<String> getOptions() { return this.options; }
private Map<String, String> id2Vote;
public Map<String, String> getId2Vote() { return id2Vote; }
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
// For GSON
private Vote()
{
this(null, 0, null, null);
}
public Vote(String creatorId, String name, List<String> options)
{
this(creatorId, System.currentTimeMillis(), name, options);
}
public Vote(String creatorId, long creationMillis, String name, List<String> options)
{
this.creatorId = creatorId;
this.creationMillis = creationMillis;
this.name = name;
this.options = options;
this.id2Vote = new MassiveMap<>();
}
// -------------------------------------------- //
// OTHER
// -------------------------------------------- //
public void setVote(MPlayer mplayer, String choice)
{
if (mplayer == null) throw new NullPointerException("mplayer");
if (choice == null) throw new NullPointerException("choice");
if (!this.getOptions().contains(choice)) throw new IllegalArgumentException(choice + " is not in " + this.getOptions());
id2Vote.put(mplayer.getId(), choice);
this.changed();
}
public String getVote(MPlayer mplayer)
{
if (mplayer == null) throw new NullPointerException("mplayer");
return this.getId2Vote().get(mplayer.getId());
}
public Faction getFaction()
{
EntityInternalMap<Vote> internalMap = (EntityInternalMap<Vote>) this.getContainer();
Faction faction = (Faction) internalMap.getEntity();
return faction;
}
public void clean()
{
Faction faction = this.getFaction();
for (Iterator<Entry<String, String>> it = this.id2Vote.entrySet().iterator(); it.hasNext();)
{
Entry<String, String> entry = it.next();
String id = entry.getKey();
// MPlayer must be a member
if ( ! faction.getMPlayerIds().contains(id))
{
it.remove();
break;
}
// And they must have the perm
MPlayer mplayer = MPlayer.get(id);
if (! MPerm.getPermVote().has(mplayer, faction, false))
{
it.remove();
break;
}
}
}
}

View File

@ -48,7 +48,7 @@ public class MigratorMPlayer001Ranks extends MigratorRoot
// Get faction
JsonElement jsonFaction = entity.get("factionId");
String factionId;
if (jsonFaction == null) factionId = MConf.get().defaultPlayerFactionId;
else factionId = jsonFaction.getAsString();

View File

@ -0,0 +1,40 @@
package com.massivecraft.factions.event;
import com.massivecraft.factions.entity.Faction;
import com.massivecraft.factions.entity.Vote;
import org.bukkit.command.CommandSender;
import org.bukkit.event.HandlerList;
public class EventFactionsVoteAdd extends EventFactionsAbstractSender
{
// -------------------------------------------- //
// REQUIRED EVENT CODE
// -------------------------------------------- //
private static final HandlerList handlers = new HandlerList();
@Override public HandlerList getHandlers() { return handlers; }
public static HandlerList getHandlerList() { return handlers; }
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
private final Faction faction;
public Faction getFaction() { return this.faction; }
private Vote vote;
public Vote getVote() { return this.vote; }
public void setVote(Vote vote) { this.vote = vote; }
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public EventFactionsVoteAdd(CommandSender sender, Faction faction, Vote vote)
{
super(sender);
this.faction = faction;
this.vote = vote;
}
}

View File

@ -0,0 +1,40 @@
package com.massivecraft.factions.event;
import com.massivecraft.factions.entity.Faction;
import com.massivecraft.factions.entity.Vote;
import org.bukkit.command.CommandSender;
import org.bukkit.event.HandlerList;
public class EventFactionsVoteRemove extends EventFactionsAbstractSender
{
// -------------------------------------------- //
// REQUIRED EVENT CODE
// -------------------------------------------- //
private static final HandlerList handlers = new HandlerList();
@Override public HandlerList getHandlers() { return handlers; }
public static HandlerList getHandlerList() { return handlers; }
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
private final Faction faction;
public Faction getFaction() { return this.faction; }
private Vote vote;
public Vote getVote() { return this.vote; }
public void setVote(Vote vote) { this.vote = vote; }
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public EventFactionsVoteRemove(CommandSender sender, Faction faction, Vote vote)
{
super(sender);
this.faction = faction;
this.vote = vote;
}
}

View File

@ -23,8 +23,8 @@ public class EventFactionsWarpRemove extends EventFactionsAbstractSender
public Faction getFaction() { return this.faction; }
private Warp warp;
public Warp getNewWarp() { return this.warp; }
public void setNewWarp(Warp warp) { this.warp = warp; }
public Warp getWarp() { return this.warp; }
public void setWarp(Warp warp) { this.warp = warp; }
// -------------------------------------------- //
// CONSTRUCT