Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First pass on stage channels #1575

Merged
merged 47 commits into from
Jun 29, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
b64f0be
First pass on stage channels
MinnDevelopment Apr 2, 2021
92766bf
Update usage of channel type
MinnDevelopment Apr 5, 2021
f85d212
Apply suggestions from code review
MinnDevelopment Apr 6, 2021
cd10a2b
Add support for speaker moderation
MinnDevelopment Apr 12, 2021
e7eefa8
Actually fire the event
MinnDevelopment Apr 12, 2021
a695147
Fix Guild#requestToSpeak
MinnDevelopment Apr 12, 2021
38fb666
Add Guild#cancelRequestToSpeak
MinnDevelopment Apr 12, 2021
5492d1d
Improve some logic
MinnDevelopment Apr 12, 2021
a7a2bbb
Merge remote-tracking branch 'origin/development' into feature/stage-…
MinnDevelopment Jun 16, 2021
0b36c38
Implement some missing features
MinnDevelopment Jun 16, 2021
6541612
Add GuildVoiceState#inviteSpeaker
MinnDevelopment Jun 16, 2021
d62eff4
Add check for missing members in voice states
MinnDevelopment Jun 17, 2021
b20ffaa
Handle topics correctly
MinnDevelopment Jun 17, 2021
08e6b9b
Fix length checks
MinnDevelopment Jun 17, 2021
7d5d7d9
Support detached voice states
MinnDevelopment Jun 17, 2021
0e0480f
Remove topic from the stage channel interface
MinnDevelopment Jun 17, 2021
f788371
Fix docs
MinnDevelopment Jun 17, 2021
6efd23c
Remove setTopic in EntityBuilder
MinnDevelopment Jun 17, 2021
ac4939d
Add support for stage instances
MinnDevelopment Jun 18, 2021
ae65a7d
Add StageInstance#delete
MinnDevelopment Jun 19, 2021
aee47e8
Add StageInstanceManager
MinnDevelopment Jun 20, 2021
2bd3b4a
Add support for StageChannel#createStageInstance
MinnDevelopment Jun 20, 2021
2b824d3
Add permission checks
MinnDevelopment Jun 20, 2021
3f915ef
Add events
MinnDevelopment Jun 20, 2021
4da9700
Fix some bugs and add docs to StageChannel
MinnDevelopment Jun 20, 2021
956111c
Add docs to StageInstance
MinnDevelopment Jun 20, 2021
31e520c
Add docs to StageInstanceManager
MinnDevelopment Jun 20, 2021
18e0d09
Fix typo
MinnDevelopment Jun 20, 2021
5a7ced0
Add docs for StageInstanceAction
MinnDevelopment Jun 20, 2021
1e71416
Add docs for request to speak
MinnDevelopment Jun 20, 2021
129970b
Add check for missing member in voice state update
MinnDevelopment Jun 20, 2021
8475439
Add event requirements
MinnDevelopment Jun 20, 2021
557b1cf
Add docs for stage instance events
MinnDevelopment Jun 20, 2021
a320977
Add docs for stage channel cache
MinnDevelopment Jun 20, 2021
0bdaef2
Add docs for Guild#requestToSpeak
MinnDevelopment Jun 20, 2021
f9b0368
Remove duplicate check
MinnDevelopment Jun 20, 2021
56c5460
Change how request to speak is implemented
MinnDevelopment Jun 20, 2021
f8d9c38
Properly remove lurkers from cache
MinnDevelopment Jun 20, 2021
5fd77d7
Add audit log enum constants
MinnDevelopment Jun 20, 2021
0deade2
Make requestToSpeak use tasks
MinnDevelopment Jun 22, 2021
68ccdd3
Add missing annotations
MinnDevelopment Jun 22, 2021
b87d1b7
Also add annotations to implementation
MinnDevelopment Jun 22, 2021
01df722
Cleanup and missing docs
MinnDevelopment Jun 22, 2021
9475f8c
Add StageInstance#getSpeakers and StageInstance#getAudience
MinnDevelopment Jun 22, 2021
532c934
Add StageInstance#requestToSpeak
MinnDevelopment Jun 28, 2021
002a443
Implement review suggestions
MinnDevelopment Jun 29, 2021
33d1038
Remaining review suggestions
MinnDevelopment Jun 29, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/main/java/net/dv8tion/jda/api/JDA.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.stream.Collectors;

/**
* The core of JDA. Acts as a registry system of JDA. All parts of the the API can be accessed starting from this class.
Expand Down Expand Up @@ -1164,6 +1165,8 @@ default GuildChannel getGuildChannelById(@Nonnull ChannelType type, long id)
return getTextChannelById(id);
case VOICE:
return getVoiceChannelById(id);
case STAGE:
return getStageChannelById(id);
case STORE:
return getStoreChannelById(id);
case CATEGORY:
Expand All @@ -1172,6 +1175,29 @@ default GuildChannel getGuildChannelById(@Nonnull ChannelType type, long id)
return null;
}

@Nonnull
default List<StageChannel> getStageChannelsByName(@Nonnull String name, boolean ignoreCase)
{
return getVoiceChannelsByName(name, ignoreCase)
.stream()
.filter(StageChannel.class::isInstance)
.map(StageChannel.class::cast)
.collect(Collectors.toList());
}

@Nullable
default StageChannel getStageChannelById(@Nonnull String id)
{
return getStageChannelById(MiscUtil.parseSnowflake(id));
}

@Nullable
default StageChannel getStageChannelById(long id)
{
VoiceChannel channel = getVoiceChannelById(id);
return channel instanceof StageChannel ? (StageChannel) channel : null;
}

/**
* {@link net.dv8tion.jda.api.utils.cache.SnowflakeCacheView SnowflakeCacheView} of
* all cached {@link net.dv8tion.jda.api.entities.Category Categories} visible to this JDA session.
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/net/dv8tion/jda/api/Permission.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ public enum Permission
MANAGE_WEBHOOKS( 29, true, true, "Manage Webhooks"),
MANAGE_EMOTES( 30, true, false, "Manage Emojis"),

REQUEST_TO_SPEAK( 32, true, true, "Request to Speak"),

UNKNOWN(-1, false, false, "Unknown");

/**
Expand Down Expand Up @@ -109,7 +111,7 @@ public enum Permission
*/
public static final long ALL_VOICE_PERMISSIONS
= Permission.getRaw(VOICE_STREAM, VOICE_CONNECT, VOICE_SPEAK, VOICE_MUTE_OTHERS,
VOICE_DEAF_OTHERS, VOICE_MOVE_OTHERS, VOICE_USE_VAD);
VOICE_DEAF_OTHERS, VOICE_MOVE_OTHERS, VOICE_USE_VAD, REQUEST_TO_SPEAK);

private final int offset;
private final long raw;
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/net/dv8tion/jda/api/entities/Category.java
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,43 @@ public interface Category extends GuildChannel
@CheckReturnValue
ChannelAction<VoiceChannel> createVoiceChannel(@Nonnull String name);

/**
* Creates a new {@link net.dv8tion.jda.api.entities.StageChannel VoiceChannel} with this Category as parent.
MinnDevelopment marked this conversation as resolved.
Show resolved Hide resolved
* For this to be successful, the logged in account has to have the
* {@link net.dv8tion.jda.api.Permission#MANAGE_CHANNEL MANAGE_CHANNEL} Permission in the {@link net.dv8tion.jda.api.entities.Guild Guild}.
MinnDevelopment marked this conversation as resolved.
Show resolved Hide resolved
*
* <p>This will copy all {@link net.dv8tion.jda.api.entities.PermissionOverride PermissionOverrides} of this Category!
* Unless the bot is unable to sync it with this category due to permission escalation.
* See {@link IPermissionHolder#canSync(GuildChannel, GuildChannel)} for details.
*
* <p>Possible {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} caused by
* the returned {@link net.dv8tion.jda.api.requests.RestAction RestAction} include the following:
* <ul>
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#MISSING_PERMISSIONS MISSING_PERMISSIONS}
* <br>The channel could not be created due to a permission discrepancy</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#MISSING_ACCESS MISSING_ACCESS}
* <br>The {@link net.dv8tion.jda.api.Permission#VIEW_CHANNEL VIEW_CHANNEL} permission was removed</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#MAX_CHANNELS MAX_CHANNELS}
* <br>The maximum number of channels were exceeded</li>
* </ul>
*
* @param name
* The name of the StageChannel to create
*
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* If the logged in account does not have the {@link net.dv8tion.jda.api.Permission#MANAGE_CHANNEL} permission
* @throws IllegalArgumentException
* If the provided name is {@code null} or empty or greater than 100 characters in length
*
* @return A specific {@link ChannelAction ChannelAction}
* <br>This action allows to set fields for the new StageChannel before creating it
*/
@Nonnull
@CheckReturnValue
ChannelAction<StageChannel> createStageChannel(@Nonnull String name);

/**
* Modifies the positional order of this Category's nested {@link #getTextChannels() TextChannels} and {@link #getStoreChannels() StoreChannels}.
* <br>This uses an extension of {@link ChannelOrderAction ChannelOrderAction}
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/net/dv8tion/jda/api/entities/ChannelType.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ public enum ChannelType
* A {@link net.dv8tion.jda.api.entities.StoreChannel StoreChannel}, Guild-Only.
*/
STORE(6, 0, true),
/**
* A {@link StageChannel StageChannel}, Guild-Only.
*/
STAGE(13, 1, true),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reminder: we have to update all usages of channel type in the library for this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming this was handled?

/**
* Unknown Discord channel type. Should never happen and would only possibly happen if Discord implemented a new
* channel type and JDA had yet to implement support for it.
Expand Down
94 changes: 94 additions & 0 deletions src/main/java/net/dv8tion/jda/api/entities/Guild.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import java.util.concurrent.Future;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
* Represents a Discord {@link net.dv8tion.jda.api.entities.Guild Guild}.
Expand Down Expand Up @@ -1147,6 +1148,8 @@ default GuildChannel getGuildChannelById(@Nonnull ChannelType type, long id)
return getTextChannelById(id);
case VOICE:
return getVoiceChannelById(id);
case STAGE:
return getStageChannelById(id);
case STORE:
return getStoreChannelById(id);
case CATEGORY:
Expand All @@ -1155,6 +1158,29 @@ default GuildChannel getGuildChannelById(@Nonnull ChannelType type, long id)
return null;
}

@Nonnull
default List<StageChannel> getStageChannelsByName(@Nonnull String name, boolean ignoreCase)
{
return getVoiceChannelsByName(name, ignoreCase)
.stream()
.filter(StageChannel.class::isInstance)
.map(StageChannel.class::cast)
.collect(Collectors.toList());
}

@Nullable
default StageChannel getStageChannelById(@Nonnull String id)
{
return getStageChannelById(MiscUtil.parseSnowflake(id));
}

@Nullable
default StageChannel getStageChannelById(long id)
{
VoiceChannel channel = getVoiceChannelById(id);
return channel instanceof StageChannel ? (StageChannel) channel : null;
}

/**
* Gets the {@link net.dv8tion.jda.api.entities.Category Category} from this guild that matches the provided id.
* This method is similar to {@link net.dv8tion.jda.api.JDA#getCategoryById(String)}, but it only checks in this
Expand Down Expand Up @@ -2253,6 +2279,10 @@ default RestAction<Ban> retrieveBan(@Nonnull User bannedUser)
@Nonnull
AudioManager getAudioManager();

@Nonnull
@CheckReturnValue
RestAction<Void> requestToSpeak();

/**
* Returns the {@link net.dv8tion.jda.api.JDA JDA} instance of this Guild
*
Expand Down Expand Up @@ -4609,6 +4639,70 @@ default ChannelAction<VoiceChannel> createVoiceChannel(@Nonnull String name)
@CheckReturnValue
ChannelAction<VoiceChannel> createVoiceChannel(@Nonnull String name, @Nullable Category parent);

/**
* Creates a new {@link net.dv8tion.jda.api.entities.StageChannel VoiceChannel} in this Guild.
MinnDevelopment marked this conversation as resolved.
Show resolved Hide resolved
* For this to be successful, the logged in account has to have the {@link net.dv8tion.jda.api.Permission#MANAGE_CHANNEL MANAGE_CHANNEL} Permission.
*
* <p>Possible {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} caused by
* the returned {@link net.dv8tion.jda.api.requests.RestAction RestAction} include the following:
* <ul>
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#MISSING_PERMISSIONS MISSING_PERMISSIONS}
* <br>The channel could not be created due to a permission discrepancy</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#MAX_CHANNELS MAX_CHANNELS}
* <br>The maximum number of channels were exceeded</li>
* </ul>
*
* @param name
* The name of the StageChannel to create
*
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* If the logged in account does not have the {@link net.dv8tion.jda.api.Permission#MANAGE_CHANNEL} permission
* @throws IllegalArgumentException
* If the provided name is {@code null} or empty or greater than 100 characters in length
*
* @return A specific {@link ChannelAction ChannelAction}
* <br>This action allows to set fields for the new StageChannel before creating it
*/
@Nonnull
@CheckReturnValue
default ChannelAction<StageChannel> createStageChannel(@Nonnull String name)
{
return createStageChannel(name, null);
}

/**
* Creates a new {@link net.dv8tion.jda.api.entities.StageChannel VoiceChannel} in this Guild.
MinnDevelopment marked this conversation as resolved.
Show resolved Hide resolved
* For this to be successful, the logged in account has to have the {@link net.dv8tion.jda.api.Permission#MANAGE_CHANNEL MANAGE_CHANNEL} Permission.
*
* <p>Possible {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} caused by
* the returned {@link net.dv8tion.jda.api.requests.RestAction RestAction} include the following:
* <ul>
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#MISSING_PERMISSIONS MISSING_PERMISSIONS}
* <br>The channel could not be created due to a permission discrepancy</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#MAX_CHANNELS MAX_CHANNELS}
* <br>The maximum number of channels were exceeded</li>
* </ul>
*
* @param name
* The name of the StageChannel to create
* @param parent
* The optional parent category for this channel, or null
*
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* If the logged in account does not have the {@link net.dv8tion.jda.api.Permission#MANAGE_CHANNEL} permission
* @throws IllegalArgumentException
* If the provided name is {@code null} or empty or greater than 100 characters in length;
* or the provided parent is not in the same guild.
*
* @return A specific {@link ChannelAction ChannelAction}
* <br>This action allows to set fields for the new StageChannel before creating it
*/
@Nonnull
@CheckReturnValue
ChannelAction<StageChannel> createStageChannel(@Nonnull String name, @Nullable Category parent);

/**
* Creates a new {@link net.dv8tion.jda.api.entities.Category Category} in this Guild.
* For this to be successful, the logged in account has to have the {@link net.dv8tion.jda.api.Permission#MANAGE_CHANNEL MANAGE_CHANNEL} Permission.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public interface IPermissionHolder extends ISnowflake
default boolean hasAccess(@Nonnull GuildChannel channel)
{
Checks.notNull(channel, "Channel");
return channel.getType() == ChannelType.VOICE
return channel.getType() == ChannelType.VOICE || channel.getType() == ChannelType.STAGE
? hasPermission(channel, Permission.VOICE_CONNECT, Permission.VIEW_CHANNEL)
: hasPermission(channel, Permission.VIEW_CHANNEL);
}
Expand Down
36 changes: 36 additions & 0 deletions src/main/java/net/dv8tion/jda/api/entities/StageChannel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.dv8tion.jda.api.entities;

import javax.annotation.Nonnull;

/**
* Represents a Stage Channel, also known as Radio Channel.
MinnDevelopment marked this conversation as resolved.
Show resolved Hide resolved
*
* <p>This is a more advanced version of a {@link VoiceChannel}
* that can be used to host events with speakers and listeners.
*/
public interface StageChannel extends VoiceChannel
{
/**
* The topic of a stage channel.
*
* @return The topic
*/
@Nonnull
String getTopic();
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public TextChannel getTextChannel()
* The {@link VoiceChannel} this invite points to.
*
* @throws IllegalStateException
* If this did not happen in a channel of type {@link ChannelType#VOICE ChannelType.VOICE}
* If this did not happen in a voice channel
MinnDevelopment marked this conversation as resolved.
Show resolved Hide resolved
*
* @return {@link VoiceChannel}
*
Expand All @@ -124,11 +124,30 @@ public TextChannel getTextChannel()
@Nonnull
public VoiceChannel getVoiceChannel()
{
if (getChannelType() != ChannelType.VOICE)
throw new IllegalStateException("The channel is not of type VOICE");
if (!(channel instanceof VoiceChannel))
throw new IllegalStateException("The channel is not of type VOICE or STAGE");
return (VoiceChannel) getChannel();
}

/**
* The {@link StageChannel} this invite points to.
*
* @throws IllegalStateException
* If this did not happen in a channel of type {@link ChannelType#STAGE ChannelType.STAGE}
*
* @return {@link StageChannel}
*
* @see #getChannel()
* @see #getChannelType()
*/
@Nonnull
public StageChannel getStageChannel()
{
if (getChannelType() != ChannelType.STAGE)
throw new IllegalStateException("The channel is not of type STAGE");
return (StageChannel) getChannel();
}

/**
* The {@link StoreChannel} this invite points to.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@

package net.dv8tion.jda.api.events.guild.voice;

import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.VoiceChannel;
import net.dv8tion.jda.api.events.UpdateEvent;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/**
Expand Down Expand Up @@ -49,6 +51,22 @@ public interface GuildVoiceUpdateEvent extends UpdateEvent<Member, VoiceChannel>
{
String IDENTIFIER = "voice-channel";

/**
* The affected {@link net.dv8tion.jda.api.entities.Member Member}
*
* @return The affected Member
*/
@Nonnull
Member getMember();

/**
* The {@link net.dv8tion.jda.api.entities.Guild Guild}
*
* @return The Guild
*/
@Nonnull
Guild getGuild();

/**
* The {@link net.dv8tion.jda.api.entities.VoiceChannel VoiceChannel} that the {@link net.dv8tion.jda.api.entities.Member Member} is moved from
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,17 +365,18 @@ default ChannelManager sync()
ChannelManager setPosition(int position);

/**
* Sets the <b><u>topic</u></b> of the selected {@link net.dv8tion.jda.api.entities.TextChannel TextChannel}.
* Sets the <b><u>topic</u></b> of the selected
* {@link net.dv8tion.jda.api.entities.TextChannel TextChannel} or {@link StageChannel StageChannel}.
*
* <p>A channel topic <b>must not</b> be more than {@code 1024} characters long!
* <br><b>This is only available to {@link net.dv8tion.jda.api.entities.TextChannel TextChannels}</b>
* <br><b>This is only available to {@link net.dv8tion.jda.api.entities.TextChannel TextChannels} and {@link StageChannel StageChannels}</b>
*
* @param topic
* The new topic for the selected {@link net.dv8tion.jda.api.entities.TextChannel TextChannel},
* The new topic for the selected channel,
* {@code null} or empty String to reset
*
* @throws UnsupportedOperationException
* If the selected {@link net.dv8tion.jda.api.entities.GuildChannel GuildChannel}'s type is not {@link net.dv8tion.jda.api.entities.ChannelType#TEXT TEXT}
* If the selected {@link net.dv8tion.jda.api.entities.GuildChannel GuildChannel}'s type is not {@link net.dv8tion.jda.api.entities.ChannelType#TEXT TEXT} nor {@link ChannelType#STAGE STAGE}
* @throws IllegalArgumentException
* If the provided topic is greater than {@code 1024} in length
*
Expand Down
Loading