Skip to content

Commit 6979519

Browse files
committed
DisbandとBQu Link挙動の修正
1 parent fe9120a commit 6979519

17 files changed

Lines changed: 284 additions & 146 deletions

.claude/settings.local.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"env": {
3+
"CLAUDE_CODE_NO_FLICKER": "0"
4+
},
5+
"permissions": {
6+
"allow": [
7+
"Bash(cat:*)",
8+
"Bash(grep:*)",
9+
"Bash(wc:*)",
10+
"Bash(find:*)",
11+
"Bash(./gradlew spotlessCheck:*)",
12+
"Bash(./gradlew build:*)",
13+
"Bash(./gradlew spotlessApply:*)",
14+
"WebFetch(domain:deepwiki.com)"
15+
]
16+
}
17+
}

CHANGELOG.md

Lines changed: 93 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -7,57 +7,67 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
* * *
99

10+
## [0.11.0]
11+
12+
### Changed
13+
14+
- **BQu Link now syncs the full member list**
15+
- Turning BQu Link ON makes all BQu party members visible in BLPC automatically.
16+
- Per-player opt-in is no longer required.
17+
- **BQu party auto-created on link**
18+
- If no BQu party exists when BQu Link is toggled ON, one is created from the BLPC party's name, members, and roles.
19+
- If a BQu party already exists, any missing BLPC members are added to it.
20+
- **Party screen stays open after BQu Link toggle**
21+
- Switching BQu Link ON or OFF no longer closes the party menu — the panel refreshes in place.
22+
- **Disband only affects the BLPC party**
23+
- Disbanding no longer touches the BQu party.
24+
- Manage the BQu party through BetterQuesting's own screen.
25+
26+
### Fixed
27+
28+
- **Disband not working after re-creating a party**
29+
- After disbanding and creating a new party, the Disband button would not show the confirmation dialog.
30+
- **Crash on world entry**
31+
- Entering a world with certain mod combinations could cause a crash.
32+
- **BQu party appearing without linking**
33+
- Creating a party in BQu would make it show up in BLPC's party list even when BQu Link was OFF.
34+
35+
[0.11.0]: https://github.com/gtexpert/BetterLinkPartyClaim/releases/tag/v0.11.0
36+
37+
* * *
38+
1039
## [0.10.0]
1140

12-
> **Wire-protocol break.** The server-to-client notification packets were
13-
> merged into one (see *Changed* below). Client and server must run the same
14-
> version — a mixed pair will not communicate notifications correctly.
41+
> **Wire-protocol break.** Client and server must run the same version — a mixed pair will not communicate notifications correctly.
1542
1643
### Changed
1744

18-
- **S→C notification packets unified**: `MessageChunkTransitNotify`,
19-
`MessagePartyEventNotify`, and `MessageClaimFailed` are now a single
20-
discriminator-multiplexed packet, `MessageClientNotify` (`int kind` +
21-
per-kind payload). Wire IDs 6–8 collapsed into ID 6; new toast types are
22-
added by appending a `KIND_*`/`EVENT_*` constant instead of a new wire ID.
23-
- **Live-update party UI**: the party panels (main menu, members, moderators,
24-
settings, create/join, transfer ownership) now stay open and refresh in
25-
place when server data changes, instead of closing on every sync. The view
26-
closes only on a structural change — the party disappearing, a permission
27-
boundary flipping, or ownership being lost.
28-
- **Free-to-join / invite flow**:
29-
- Clicking a party in the create/join screen now opens the party menu
30-
directly once the join succeeds, instead of just dismissing the screen.
31-
- Full free-to-join parties are listed but shown grayed and non-clickable
32-
rather than hidden, so a previously-available party doesn't silently vanish.
33-
- **Documentation**: `CLAUDE.md`, the architecture skill, and the code-review
34-
agent updated to describe the discriminator-multiplexed packets, the
35-
live-update widget patterns, and the shared `PartyWidgets` helpers.
45+
- **Live-update party UI**
46+
- Party panels now stay open and refresh in place when data changes, instead of closing on every sync.
47+
- Panels only close when the party is gone, permissions change, or ownership is lost.
48+
- **Free-to-join / invite flow**
49+
- Joining a party from the create/join screen now opens the party menu directly.
50+
- Full parties are shown grayed out instead of hidden.
3651

3752
### Fixed
3853

39-
- **Stale party data in open panels**: after a disband, ownership transfer, or
40-
kick performed by another player, an open party panel could keep showing the
41-
old state (and, for the main menu, leave a stale "open sub-panel" button
42-
behind). Panels now refresh or close correctly on every sync.
43-
- **Stale values in the Settings panel**: every server sync replaces the
44-
cached party object, so the panel could display an out-of-date name, color,
45-
member count, or toggle state. All Settings widgets now read the live party.
46-
- **Silent join failures**: trying to join a party that was disbanded, is no
47-
longer free-to-join, or whose invite expired now shows a "Could not join the
48-
party" toast instead of doing nothing visible. (Capacity failures already
49-
showed "Party is full".)
50-
- **Self-notification toasts**: the player who joins a party no longer receives
51-
a "you joined" toast for themselves, and the player who disbands a party no
52-
longer receives a "party disbanded" toast.
53-
- **Optimistic-UI desync on rejected actions**: when the server rejects a party
54-
action (e.g. a stale click), the rejecting player's client now receives a
55-
corrective sync so the UI no longer shows a change that didn't take effect.
56-
- **Moderators panel after promotion**: a viewer who is promoted to OWNER while
57-
the panel is open now gets the role-cycle controls without having to reopen.
58-
- **Memory leaks**: orphaned sub-panel handlers were accumulating each time the
59-
main menu rebuilt (they are now created once and reused), and empty
60-
invader-tracking sets were left behind on player logout.
54+
- **Stale party data in open panels**
55+
- After a disband, ownership transfer, or kick by another player, open panels could keep showing outdated state.
56+
- Panels now refresh or close correctly.
57+
- **Stale values in the Settings panel**
58+
- Name, color, member count, and toggle states could show outdated values after a server sync.
59+
- All settings now read live data.
60+
- **Silent join failures**
61+
- Trying to join a disbanded, no-longer-free, or expired-invite party now shows a toast instead of doing nothing.
62+
- **Self-notification toasts**
63+
- The player who joins or disbands a party no longer receives their own toast notification.
64+
- **UI desync on rejected actions**
65+
- When the server rejects a party action, the client now receives a corrective sync so the UI matches the actual state.
66+
- **Moderators panel after promotion**
67+
- A player promoted to OWNER while the panel is open now sees the role-cycle controls without reopening.
68+
- **Memory leaks**
69+
- Sub-panel handlers were accumulating on each menu rebuild.
70+
- Empty tracking sets were left behind on player logout.
6171

6272
[0.10.0]: https://github.com/gtexpert/BetterLinkPartyClaim/releases/tag/v0.10.0
6373

@@ -67,27 +77,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6777

6878
### Changed
6979

70-
- **Network layer refactor**: split the network handlers along the side
71-
boundary. `IMessage` classes stay in `common/network/` and must not
72-
reference any `@SideOnly` types in their bytecode; client-bound (S→C)
73-
handlers now live in `client/network/` and are gated with
74-
`@SideOnly(Side.CLIENT)`. Server-side registration uses a no-op handler
75-
so the dedicated server never class-loads client code.
76-
- **`MessagePartyAction` dispatcher extracted**: the 22 action arms moved
77-
from the inner `Handler` into `common/network/party/PartyActionDispatcher`,
78-
one private method per action. Wire-protocol IDs and `ACTION_*` constants
79-
are unchanged.
80-
- **`ModNetwork` registration**: client-bound messages are listed once in
81-
`CLIENT_BOUND_MESSAGES` and installed via `ClientPacketHandlers.installAll()`
82-
on the client. Wire IDs (0–8) are preserved.
80+
- **Network layer split by side**
81+
- Server-side and client-side network handlers are now separated to prevent dedicated-server class-loading issues.
8382

8483
### Fixed
8584

86-
- **Dedicated-server crash on party creation**:
87-
`NoSuchMethodError: EnumDyeColor.func_193350_e()``EnumDyeColor.getColorValue()`
88-
is `@SideOnly(Side.CLIENT)` in vanilla 1.12.2 and is not present on the
89-
dedicated server. The default party color is now stored as the inlined
90-
RGB constant instead.
85+
- **Dedicated-server crash on party creation**
86+
- Creating a party on a dedicated server no longer crashes due to a missing client-only color method.
9187

9288
[0.9.0]: https://github.com/gtexpert/BetterLinkPartyClaim/releases/tag/v0.9.0
9389

@@ -99,54 +95,46 @@ Initial release.
9995

10096
### Added
10197

102-
- **Chunk claiming**: claim, unclaim, and force-load chunks via a full-screen
103-
ModularUI map (`M` key) and a client-side minimap HUD (`N` key to toggle).
104-
Bulk operations are supported by drag selection, and dedicated buttons allow
105-
unclaiming or unloading every chunk owned by the player at once.
106-
- **Server-authoritative party system**: parties are persisted under
107-
`world/betterlink/pc/parties/<id>.dat` with three roles (`OWNER`, `ADMIN`,
108-
`MEMBER`) and a configurable member cap.
109-
- **Trust levels** (`NONE`, `ALLY`, `MEMBER`, `MODERATOR`, `OWNER`) per
110-
protected action: block edit, block interaction, attacking entities, and item
111-
use. A separate trust level controls fake-player automation mods such as
112-
BuildCraft and EnderIO.
113-
- **Allies and enemies**: party-versus-party relations replace the previous
114-
per-player allowlists. Enemies are denied protection access regardless of
115-
trust level.
116-
- **Explosion protection toggle** for claimed chunks (per party).
117-
- **Free-to-join parties** with optional invitation flow, configurable
118-
description, color, and display name.
119-
- **Modular party manager UI** with tabbed panels for party info, protection,
120-
allies, enemies, members, and invitations. Players and parties are filterable
121-
via a search field, and all rows expose tooltips for available actions.
122-
- **Toast notifications** for party events (member joined/left, kicked,
123-
disbanded, ownership transferred, role changed, BQu link/unlink, party full)
124-
and a dedicated stream for claim-limit failures.
125-
- **Transit notifications** announcing when a member returns home, an ally
126-
visits, or an enemy enters or leaves a claimed area.
127-
- **BetterQuesting integration** (optional): an opt-in switch links a player's
128-
BLPC party to a BQu party. The active party provider is selected per player,
129-
so non-linked players never modify BQu state.
130-
- **Chunk map rendering**: async terrain colorization with a `DynamicTexture`
131-
cache; player position, claim ownership, and party color overlays are drawn
132-
on top of the rendered map.
133-
- **Chat commands** (Forge `CommandTreeBase` rooted at `/blpc`):
134-
- Public (level 0): `list`, `info <party>`, `me`, `here`, `claims`,
135-
`invites`, `accept <party>`, `decline <party>`, `leave`.
136-
- Operator only (level 3, under `/blpc admin`): `move-owner <party> <player>`,
137-
`kick <party> <player>`, `disband <party>`.
138-
- All commands provide tab completion for parties, members, and pending
139-
invitations as appropriate.
140-
- **Localization**: full English (`en_us`) and Japanese (`ja_jp`) translations.
141-
- **Persistence**: party data, BQu link state, and chunk claims are saved via
142-
`BLPCSaveHandler`; a one-time migration imports legacy data from the
143-
pre-FTB-Lib layout.
98+
- **Chunk claiming**
99+
- Claim, unclaim, and force-load chunks via a full-screen map (`M` key) and a minimap HUD (`N` key to toggle).
100+
- Supports drag selection and bulk unclaim/unload buttons.
101+
- **Party system**
102+
- Server-authoritative parties with three roles (Owner, Admin, Member) and a configurable member cap.
103+
- Persisted per world.
104+
- **Trust levels**
105+
- Per-action trust settings (block edit, block interaction, attacking entities, item use) with levels from None to Owner.
106+
- A separate setting controls fake-player automation mods.
107+
- **Allies and enemies**
108+
- Party-versus-party relations.
109+
- Allies share protection access; enemies are denied regardless of trust level.
110+
- **Explosion protection**
111+
- Per-party toggle for claimed chunks.
112+
- **Free-to-join parties**
113+
- Optional open-join mode with invitation flow, description, color, and display name.
114+
- **Party manager UI**
115+
- Tabbed panels for party info, protection, allies, enemies, members, and invitations.
116+
- Searchable player/party lists with tooltips.
117+
- **Toast notifications**
118+
- Party events: join, leave, kick, disband, ownership transfer, role change, BQu link/unlink, party full.
119+
- Claim-limit failures.
120+
- **Transit notifications**
121+
- Alerts when a member returns home, an ally visits, or an enemy enters/leaves claimed territory.
122+
- **BetterQuesting integration** (optional)
123+
- Opt-in switch to link a BLPC party to a BQu party.
124+
- Non-linked players are unaffected.
125+
- **Chunk map rendering**
126+
- Async terrain colorization with player position, claim ownership, and party color overlays.
127+
- **Chat commands**
128+
- Public: `/blpc list`, `info`, `me`, `here`, `claims`, `invites`, `accept`, `decline`, `leave`.
129+
- Operator: `/blpc admin move-owner`, `kick`, `disband`.
130+
- All commands support tab completion.
131+
- **Localization**
132+
- English and Japanese translations.
144133

145134
### Compatibility
146135

147136
- Minecraft 1.12.2, Forge.
148137
- Required: ModularUI 3.1.5+.
149-
- Optional: BetterQuesting (for party integration), JourneyMap (for the
150-
minimap integration hooks).
138+
- Optional: BetterQuesting (party integration), JourneyMap (minimap integration).
151139

152140
[0.8.0]: https://github.com/gtexpert/BetterLinkPartyClaim/releases/tag/v0.8.0

buildscript.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ autoUpdateBuildScript = false
3030
minecraftVersion = 1.12.2
3131

3232
# Debug mod compatibility
33-
debug_all = false
33+
debug_all = true
3434
debug_bqu = false
3535
debug_jmap = false
3636

src/main/java/com/github/gtexpert/blpc/api/party/IPartyProvider.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,17 @@ default boolean hasNativeParty(UUID playerUUID) {
7070
return getPartyName(playerUUID) != null;
7171
}
7272

73+
/**
74+
* Ensures a native party exists for the owner with the same members as the
75+
* given BLPC party. Creates the native party if absent, adds missing
76+
* members, and maps roles. Returns {@code true} if the native party is
77+
* ready for linking after this call.
78+
*/
79+
default boolean ensureNativePartyWithMembers(EntityPlayerMP owner,
80+
com.github.gtexpert.blpc.common.party.Party blpcParty) {
81+
return hasNativeParty(owner.getUniqueID());
82+
}
83+
7384
/** Syncs party data to all connected clients after mutations. */
7485
void syncToAll();
7586

src/main/java/com/github/gtexpert/blpc/client/gui/party/CreatePanel.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public static ModularPanel build() {
4040
public static ModularPanel build(IPanelHandler reopener) {
4141
UUID playerId = Minecraft.getMinecraft().player.getUniqueID();
4242

43-
ModularPanel panel = new ModularPanel(PANEL_ID);
43+
ModularPanel panel = new ModularPanel(PartyWidgets.uniquePanelId(PANEL_ID));
4444
panel.size(PartyWidgets.STANDARD_W, PartyWidgets.STANDARD_H);
4545

4646
PartyWidgets.addHeader(panel, "blpc.party.create_title");

src/main/java/com/github/gtexpert/blpc/client/gui/party/MainPanel.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public static ModularPanel build(UUID playerId, IPanelHandler reopener) {
5151

5252
UUID partyId = party.getPartyId();
5353

54-
ModularPanel panel = new ModularPanel(PANEL_ID);
54+
ModularPanel panel = new ModularPanel(PartyWidgets.uniquePanelId(PANEL_ID));
5555
panel.size(PartyWidgets.STANDARD_W, PartyWidgets.STANDARD_H);
5656

5757
panel.child(new ScrollingTextWidget(IKey.dynamic(() -> {
@@ -80,7 +80,7 @@ public static ModularPanel build(UUID playerId, IPanelHandler reopener) {
8080
rebuildMenu(menuList, panel, partyId, playerId, nav);
8181

8282
IPanelHandler disbandHandler = IPanelHandler.simple(
83-
panel, (pp, player) -> ConfirmDialog.builder("blpc.party.dialog.disband")
83+
panel, (pp, player) -> ConfirmDialog.builder(PartyWidgets.uniquePanelId("blpc.party.dialog.disband"))
8484
.title("blpc.party.disband_confirm_title")
8585
.message("blpc.party.disband_confirm_msg")
8686
.yesLabel("blpc.party.disband_yes")
@@ -98,7 +98,6 @@ public static ModularPanel build(UUID playerId, IPanelHandler reopener) {
9898
.setEnabledIf(w -> isOwner(partyId, playerId)));
9999

100100
PartyWidgets.addSyncRefreshListener(panel, () -> {
101-
// Party gone: cascade-close sub-panels too.
102101
if (ClientPartyCache.getPartyByPlayer(playerId) == null) {
103102
panel.closeIfOpen();
104103
return;

src/main/java/com/github/gtexpert/blpc/client/gui/party/MembersPanel.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public static ModularPanel build(Party party) {
3333
boolean canManage = myRole != null && myRole.canInvite();
3434
UUID partyId = party.getPartyId();
3535

36-
ModularPanel panel = new ModularPanel(PANEL_ID);
36+
ModularPanel panel = new ModularPanel(PartyWidgets.uniquePanelId(PANEL_ID));
3737
PartyRole[] myRoleRef = { myRole };
3838

3939
LiveSearchableList<PlayerEntry> membersList = new LiveSearchableList<>(

src/main/java/com/github/gtexpert/blpc/client/gui/party/ModeratorsPanel.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public static ModularPanel build(Party party) {
3232
UUID partyId = party.getPartyId();
3333
boolean[] isOwnerRef = { party.getRole(playerId) == PartyRole.OWNER };
3434

35-
ModularPanel panel = new ModularPanel(PANEL_ID);
35+
ModularPanel panel = new ModularPanel(PartyWidgets.uniquePanelId(PANEL_ID));
3636
panel.size(PartyWidgets.STANDARD_W, PartyWidgets.STANDARD_H);
3737
PartyWidgets.addHeader(panel, "blpc.party.moderators_title");
3838

src/main/java/com/github/gtexpert/blpc/client/gui/party/PartyWidgets.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,18 @@ public final class PartyWidgets {
4949

5050
private PartyWidgets() {}
5151

52+
/**
53+
* Per-instance unique panel name suffix. MUI's {@code PanelManager.panelHandlerMap}
54+
* keys on {@link ModularPanel#getName()} and never removes entries; a fresh
55+
* {@code IPanelHandler.simple(...)} that opens the same panel name silently
56+
* redirects to the stale first handler ("Using existing panel handler!" in
57+
* MUI log). Appending a monotonic suffix to every rebuilt panel/dialog name
58+
* makes each instance unique so the lookup hits the current handler.
59+
*/
60+
public static String uniquePanelId(String base) {
61+
return base + "#" + System.nanoTime();
62+
}
63+
5264
/** Centered title + close button at the top of the panel. */
5365
public static void addHeader(ModularPanel panel, IKey title) {
5466
panel.child(title.color(GuiColors.WHITE).shadow(true)

src/main/java/com/github/gtexpert/blpc/client/gui/party/SettingsPanel.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public class SettingsPanel {
5050
private static final TrustLevel[] CYCLE_LEVELS = { TrustLevel.NONE, TrustLevel.ALLY, TrustLevel.MEMBER };
5151

5252
public static ModularPanel build(Party initialParty) {
53-
ModularPanel panel = new ModularPanel(PANEL_ID);
53+
ModularPanel panel = new ModularPanel(PartyWidgets.uniquePanelId(PANEL_ID));
5454
panel.size(PartyWidgets.LARGE_W, PartyWidgets.LARGE_H);
5555

5656
UUID partyId = initialParty.getPartyId();
@@ -87,7 +87,7 @@ private static IWidget buildPartyInfoPage(Supplier<Party> partyRef, ModularPanel
8787

8888
// Pre-create handlers to avoid "same panel handler already exists" on repeated clicks.
8989
IPanelHandler renameHandler = IPanelHandler.simple(panel, (pp, player) -> InputDialog
90-
.builder("blpc.party.dialog.rename")
90+
.builder(PartyWidgets.uniquePanelId("blpc.party.dialog.rename"))
9191
.title("blpc.party.name_field")
9292
.defaultValue(partyRef.get().getName())
9393
.confirmLabel("blpc.map.yes")
@@ -98,7 +98,7 @@ private static IWidget buildPartyInfoPage(Supplier<Party> partyRef, ModularPanel
9898
.build(), true);
9999

100100
IPanelHandler descHandler = IPanelHandler.simple(panel, (pp, player) -> InputDialog
101-
.builder("blpc.party.dialog.description")
101+
.builder(PartyWidgets.uniquePanelId("blpc.party.dialog.description"))
102102
.title("blpc.party.description_field")
103103
.defaultValue(partyRef.get().getDescription())
104104
.confirmLabel("blpc.map.yes")

0 commit comments

Comments
 (0)