3030import java .util .Properties ;
3131import java .util .concurrent .ConcurrentHashMap ;
3232import java .util .function .BiConsumer ;
33+ import java .util .function .BiFunction ;
3334import java .util .function .Consumer ;
3435import java .util .regex .Matcher ;
3536import java .util .regex .Pattern ;
@@ -48,8 +49,9 @@ public final class DiscordBridgePlugin extends JavaPlugin {
4849 private DiscordBotConnection botConnection ;
4950 private boolean serverStartMessageSent ;
5051 private boolean serverStopMessageSent ;
51- private final Map <String , String > discordUserToAvatarUrl = new ConcurrentHashMap <>();
52+ private final Map <String , String > hytaleUsernameToAvatarUrl = new ConcurrentHashMap <>();
5253 private final Map <String , String > hytaleUsernameToDiscordUserId = new ConcurrentHashMap <>();
54+ private volatile boolean isShuttingDown = false ;
5355
5456 public DiscordBridgePlugin (@ NotNull JavaPluginInit init ) {
5557 super (init );
@@ -88,26 +90,35 @@ protected void setup() {
8890 return ;
8991 }
9092
91- BiConsumer <String , String > avatarSetter = (userId , url ) -> {
92- discordUserToAvatarUrl .put (userId , url );
93- saveMappings ();
94- };
95- BiConsumer <String , String > linkSetter = (username , userId ) -> {
96- hytaleUsernameToDiscordUserId .put (username , userId );
97- saveMappings ();
98- };
99- Consumer <String > unlinkUser = userId -> {
100- hytaleUsernameToDiscordUserId .entrySet ().removeIf (entry -> entry .getValue ().equals (userId ));
101- saveMappings ();
102- };
103- this .botConnection = new DiscordBotConnection (cfg , getLogger (), this ::relayDiscordMessage , avatarSetter , linkSetter , unlinkUser );
93+ BiConsumer <String , String > avatarSetter = (username , url ) -> {
94+ hytaleUsernameToAvatarUrl .put (username , url );
95+ saveMappings ();
96+ };
97+ BiFunction <String , String , Boolean > linkSetter = (username , userId ) -> {
98+ if (hytaleUsernameToDiscordUserId .containsKey (username ) && !hytaleUsernameToDiscordUserId .get (username ).equals (userId )) {
99+ return false ;
100+ }
101+ hytaleUsernameToDiscordUserId .put (username , userId );
102+ saveMappings ();
103+ return true ;
104+ };
105+ Consumer <String > unlinkUser = userId -> {
106+ hytaleUsernameToDiscordUserId .entrySet ().removeIf (entry -> entry .getValue ().equals (userId ));
107+ saveMappings ();
108+ };
109+ BiFunction <String , String , Boolean > isLinked = (username , userId ) -> {
110+ String linkedUserId = hytaleUsernameToDiscordUserId .get (username );
111+ return linkedUserId != null && linkedUserId .equals (userId );
112+ };
113+ this .botConnection = new DiscordBotConnection (cfg , getLogger (), this ::relayDiscordMessage , avatarSetter , linkSetter , unlinkUser , isLinked );
104114 getLogger ().at (Level .INFO ).log ("Discord bot connection initialized" );
105115 }
106116
107117 @ Override
108118 protected void start () {
109119 this .serverStartMessageSent = false ;
110120 this .serverStopMessageSent = false ;
121+ this .isShuttingDown = false ;
111122
112123 if (botConnection == null ) {
113124 getLogger ().at (Level .INFO ).log ("Skipping Discord bot start - not configured" );
@@ -132,6 +143,7 @@ protected void start() {
132143 @ Override
133144 protected void shutdown () {
134145 getLogger ().at (Level .INFO ).log ("Shutting down Discord bridge..." );
146+ this .isShuttingDown = true ;
135147 sendServerStopMessage ();
136148 if (botConnection != null ) {
137149 botConnection .shutdown ();
@@ -161,7 +173,7 @@ private void onPlayerChat(@NotNull PlayerChatEvent event) {
161173 }
162174 String username = event .getSender ().getUsername ();
163175 String discordUserId = hytaleUsernameToDiscordUserId .get (username );
164- String avatarUrl = discordUserId != null ? discordUserToAvatarUrl .get (discordUserId ) : null ;
176+ String avatarUrl = discordUserId != null ? hytaleUsernameToAvatarUrl .get (username ) : null ;
165177 botConnection .sendWebhookMessage (webhookUrl , event .getSender ().getUsername (), cleaned , avatarUrl );
166178 }
167179
@@ -173,6 +185,9 @@ private void onPlayerConnect(@NotNull PlayerConnectEvent event) {
173185 }
174186
175187 private void onPlayerDisconnect (@ NotNull PlayerDisconnectEvent event ) {
188+ if (isShuttingDown ) {
189+ return ;
190+ }
176191 DiscordBridgeConfig cfg = config .get ();
177192 EventsConfig events = cfg .getEventsConfig ();
178193 MessagesConfig messages = cfg .getMessagesConfig ();
@@ -399,8 +414,8 @@ private void loadMappings() {
399414 for (String key : props .stringPropertyNames ()) {
400415 String value = props .getProperty (key );
401416 if (key .startsWith ("avatar." )) {
402- String userId = key .substring (7 );
403- discordUserToAvatarUrl .put (userId , value );
417+ String username = key .substring (7 );
418+ hytaleUsernameToAvatarUrl .put (username , value );
404419 } else if (key .startsWith ("link." )) {
405420 String username = key .substring (5 );
406421 hytaleUsernameToDiscordUserId .put (username , value );
@@ -414,7 +429,7 @@ private void loadMappings() {
414429 private void saveMappings () {
415430 Path mappingsFile = getDataDirectory ().resolve ("mappings.properties" );
416431 Properties props = new Properties ();
417- for (Map .Entry <String , String > entry : discordUserToAvatarUrl .entrySet ()) {
432+ for (Map .Entry <String , String > entry : hytaleUsernameToAvatarUrl .entrySet ()) {
418433 props .setProperty ("avatar." + entry .getKey (), entry .getValue ());
419434 }
420435 for (Map .Entry <String , String > entry : hytaleUsernameToDiscordUserId .entrySet ()) {
0 commit comments