Skip to content

Commit

Permalink
bug(Character): Fix multiple variant bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
Kruptein authored Jan 14, 2024
1 parent 5e13397 commit cc89444
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 23 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ tech changes will usually be stripped from release notes for the public
- Polygon edit UI: was not taking rotation of shape into account
- Teleport: shapes would not be removed on the old location until a refresh
- Dice tool: would not send zero results when dice list is empty
- Character: a collection of bugs with variants have been fixed
- [server] log spam of "unknown" shape when temporary shapes are moved

## [2023.3.0] - 2023-09-17
Expand Down
39 changes: 26 additions & 13 deletions client/src/game/dropAsset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { i18n } from "../i18n";
import { requestAssetOptions } from "./api/emits/asset";
import { sendShapesMove } from "./api/emits/shape/core";
import { getLocalId, getShape } from "./id";
import { compositeState } from "./layers/state";
import type { BaseTemplate } from "./models/templates";
import { moveShapes } from "./operations/movement";
import { applyTemplate } from "./shapes/templates";
Expand Down Expand Up @@ -63,21 +64,33 @@ async function dropHelper(
throw new Error("Unknown character ID encountered");
}
const shapeId = getLocalId(character.shapeId, false);

if (shapeId !== undefined) {
const shape = getShape(shapeId)!;
await moveShapes([shape], Vector.fromPoints(shape.center, location), false);
} else {
sendShapesMove({
shapes: [character.shapeId],
target: {
layer: floorState.currentLayer.value!.name,
floor: floorState.currentFloor.value!.name,
location: locationSettingsState.raw.activeLocation,
x: location.x,
y: location.y,
},
});
let shape = getShape(shapeId);
// bunch of fuckery to patch toggle composites
if (shape !== undefined) {
const compositeParent = compositeState.getCompositeParent(shapeId);
if (compositeParent !== undefined) {
shape = getShape(compositeParent.activeVariant);
}
}
if (shape !== undefined && shape.options?.skipDraw !== true) {
await moveShapes([shape], Vector.fromPoints(shape.center, location), false);
return;
}
}

sendShapesMove({
shapes: [character.shapeId],
target: {
layer: floorState.currentLayer.value!.name,
floor: floorState.currentFloor.value!.name,
location: locationSettingsState.raw.activeLocation,
x: location.x,
y: location.y,
},
});

return;
}
await dropAsset({ assetId: assetInfo.assetId, imageSource: `/static/assets/${assetInfo.assetHash}` }, location);
Expand Down
1 change: 1 addition & 0 deletions client/src/game/interfaces/shapes/toggleComposite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { IShape } from "../shape";

export interface IToggleComposite extends IShape {
get variants(): readonly { id: LocalId; name: string }[];
get activeVariant(): LocalId;

addVariant: (uuid: LocalId, name: string, sync: boolean) => void;
removeVariant: (id: LocalId, syncTo: Sync) => void;
Expand Down
4 changes: 4 additions & 0 deletions client/src/game/shapes/variants/toggleComposite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ export class ToggleComposite extends Shape implements IToggleComposite {
return this._variants;
}

get activeVariant(): LocalId {
return this.active_variant;
}

addVariant(id: LocalId, name: string, sync: boolean): void {
const variant = { id, name };
this._variants.push(variant);
Expand Down
10 changes: 9 additions & 1 deletion client/src/game/systems/characters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { ApiCharacter } from "../../../apiTypes";
import { find } from "../../../core/iter";
import { getGlobalId, getLocalId, getShape, type LocalId } from "../../id";
import type { IShape } from "../../interfaces/shape";
import type { IToggleComposite } from "../../interfaces/shapes/toggleComposite";
import { selectedState } from "../selected/state";

import type { CharacterId } from "./models";
Expand Down Expand Up @@ -64,7 +65,14 @@ class CharacterSystem implements ShapeSystem {
const shapeId = mutable.characters.get(character)?.shapeId;
if (shapeId) {
const localId = getLocalId(shapeId, false);
if (localId) return getShape(localId);
if (localId) {
const shape = getShape(localId);
if (shape === undefined) return undefined;
if (shape.type === "togglecomposite") {
return getShape((shape as IToggleComposite).activeVariant);
}
return shape;
}
}
}
}
Expand Down
14 changes: 11 additions & 3 deletions client/src/game/ui/contextmenu/ShapeContext.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import { toTemplate } from "../../shapes/templates";
import { deleteShapes } from "../../shapes/utils";
import { accessSystem } from "../../systems/access";
import { sendCreateCharacter } from "../../systems/characters/emits";
import { characterState } from "../../systems/characters/state";
import { floorSystem } from "../../systems/floors";
import { floorState } from "../../systems/floors/state";
import { gameState } from "../../systems/game/state";
Expand Down Expand Up @@ -306,7 +305,16 @@ async function saveTemplate(): Promise<void> {
}
// CHARACTER
const hasCharacter = computed(() => characterState.reactive.activeCharacterId !== undefined);
const canHaveCharacter = computed(() => {
const selection = selectedState.reactive.selected;
if (selection.size !== 1) return false;
const shapeId = [...selection][0]!;
const compParent = compositeState.getCompositeParent(shapeId);
if (compParent?.variants.some((v) => getShape(v.id)?.character !== undefined) ?? false) return false;
const shape = getShape(shapeId);
if (shape?.assetId === undefined) return false;
return true;
});
function createCharacter(): void {
close();
Expand Down Expand Up @@ -469,7 +477,7 @@ const floors = toRef(floorState.reactive, "floors");
<li v-if="!selectionIncludesSpawnToken && gameState.reactive.isDm && canBeSaved" @click="saveTemplate">
{{ t("game.ui.templates.save") }}
</li>
<li v-if="isOwned && !hasCharacter" @click="createCharacter">Create character</li>
<li v-if="isOwned && canHaveCharacter" @click="createCharacter">Create character</li>
</template>
<template v-else>
<li>
Expand Down
13 changes: 9 additions & 4 deletions client/src/game/ui/settings/shape/VariantSwitcher.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { computed, toRef } from "vue";
import { useToast } from "vue-toastification";
import { cloneP } from "../../../../core/geometry";
import { InvalidationMode, SERVER_SYNC, SyncMode } from "../../../../core/models/types";
Expand All @@ -12,6 +13,7 @@ import { compositeState } from "../../../layers/state";
import { ToggleComposite } from "../../../shapes/variants/toggleComposite";
const modals = useModal();
const toast = useToast();
const vState = activeShapeStore.state;
Expand Down Expand Up @@ -65,14 +67,17 @@ async function addVariant(): Promise<void> {
return;
}
const name = await modals.prompt("What name should this variant have?", "Name variant");
if (name === undefined) return;
const newShape = await dropAsset(
{ imageSource: `/static/assets/${asset.fileHash}`, assetId: asset.id },
shape.refPoint,
);
if (newShape === undefined) return;
const name = await modals.prompt("What name should this variant have?", "Name variant");
if (name === undefined) return;
if (newShape === undefined) {
toast.error("Something went wrong trying to add this variant.");
return;
}
let parent = compositeParent.value;
if (parent === undefined) {
Expand Down
30 changes: 29 additions & 1 deletion server/src/api/socket/shape/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,21 @@ async def remove_shapes(sid: str, raw_data: Any):
if shape.group:
group_ids.add(shape.group)

if shape.character_id is None:
is_char_related = shape.character_id is not None
# ToggleComposite patches
if not is_char_related:
parent = None
if shape.composite_parent:
parent = shape.composite_parent[0].parent
elif shape.type_ == "togglecomposite":
parent = shape
if parent:
for csa in parent.shape_variants:
if csa.variant.character_id is not None:
is_char_related = True
break

if not is_char_related:
file_hash_to_clean = None
if shape.type_ == "assetrect":
rect = cast(AssetRect, shape.subtype)
Expand Down Expand Up @@ -396,6 +410,12 @@ async def move_shapes(sid: str, raw_data: Any):
shapes = []
old_floor = None
for shape in _get_shapes_from_uuids(data.shapes, False):
# toggle composite patch
parent = None
if shape.composite_parent:
parent = shape.composite_parent[0].parent
shape = Shape.get_by_id(parent.subtype.active_variant)

layer = target_layer
if shape.layer:
if old_floor is None:
Expand All @@ -404,8 +424,16 @@ async def move_shapes(sid: str, raw_data: Any):
elif layer is None:
logger.warn("Attempt to move a shape without layer info")
continue

shapes.append((shape, layer))

if parent:
shapes.append((parent, layer))
for csa in parent.shape_variants:
variant = csa.variant
if variant != shape:
shapes.append((variant, layer))

if old_floor:
await send_remove_shapes(
[sh.uuid for sh, _ in shapes], room=old_floor.location.get_path()
Expand Down
1 change: 0 additions & 1 deletion server/src/db/models/composite_shape_association.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,3 @@ class CompositeShapeAssociation(BaseDbModel):
variant = ForeignKeyField(Shape, backref="composite_parent", on_delete="CASCADE")
parent = ForeignKeyField(Shape, backref="shape_variants", on_delete="CASCADE")
name = cast(str, TextField())
name = cast(str, TextField())

0 comments on commit cc89444

Please sign in to comment.