Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion client/src/apiTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,7 @@ export interface ToggleCompositeVariant {
shape: GlobalId;
variant: GlobalId;
}
export interface TypeIdModel {}
export interface TypeIdModel { }
export interface ApiLocation {
id: number;
name: string;
Expand All @@ -867,6 +867,7 @@ export interface ApiOptionalLocationOptions {
unit_size?: number | null;
unit_size_unit?: string | null;
use_grid?: boolean | null;
use_origin_marker?: boolean | null;
full_fow?: boolean | null;
fow_opacity?: number | null;
fow_los?: boolean | null;
Expand All @@ -891,6 +892,7 @@ export interface ApiLocationOptions {
unit_size: number;
unit_size_unit: string;
use_grid: boolean;
use_origin_marker: boolean;
full_fow: boolean;
fow_opacity: number;
fow_los: boolean;
Expand Down
1 change: 1 addition & 0 deletions client/src/fa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export function loadFontAwesome(): void {
faCopy,
faCompass,
faCommentDots,
faLocationDot,
faCut,
faDAndD,
faDiceD20,
Expand Down
2 changes: 2 additions & 0 deletions client/src/game/api/events/location.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ function setLocationOptions(id: number | undefined, options: ApiOptionalLocation
locationSettingsSystem.setUnitSize(options.unit_size ?? undefined, id, false);
if (overwrite_all || options.unit_size_unit !== undefined)
locationSettingsSystem.setUnitSizeUnit(options.unit_size_unit ?? undefined, id, false);
if (overwrite_all || options.use_origin_marker !== undefined)
locationSettingsSystem.setUseOriginMarker(options.use_origin_marker ?? undefined, id, false);
if (overwrite_all || options.drop_ratio !== undefined)
locationSettingsSystem.setDropRatio(options.drop_ratio ?? undefined, id, false);

Expand Down
22 changes: 21 additions & 1 deletion client/src/game/layers/variants/grid.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import { toGP } from "../../../core/geometry";
import { DEFAULT_HEX_RADIUS, DEFAULT_GRID_SIZE, SQRT3, GridType } from "../../../core/grid";
import type { IGridLayer } from "../../interfaces/layers/grid";
import { FontAwesomeIcon } from "../../shapes/variants/fontAwesomeIcon";
import type { SvgDisplayOverrides } from "../../shapes/variants/fontAwesomeIcon";
import { floorState } from "../../systems/floors/state";
import { gameState } from "../../systems/game/state";
import { positionState } from "../../systems/position/state";
import { locationSettingsState } from "../../systems/settings/location/state";
import { playerSettingsState } from "../../systems/settings/players/state";

import { Layer } from "./layer";

export class GridLayer extends Layer implements IGridLayer {
displayOverrides: SvgDisplayOverrides = { fill: "rgba(255,0,0,0.4)", stroke: "black", strokeWidth: "10" };
originIcon: FontAwesomeIcon = new FontAwesomeIcon({ prefix: "fas", iconName: "location-dot" }, toGP(0, 0), 40, {
svgDisplayOverrides: this.displayOverrides,
});
originIconSize = { width: 30, height: 40 };

invalidate(): void {
this.valid = false;
}
Expand All @@ -19,6 +29,17 @@ export class GridLayer extends Layer implements IGridLayer {

draw(_doClear?: boolean): void {
if (!this.valid) {
this.clear();
if (locationSettingsState.raw.useOriginMarker.value && gameState.raw.isDm) {
const ctx = this.ctx;
const state = positionState.readonly;
console.log(state.zoom);
this.originIcon.draw(ctx, false, {
center: toGP(0, -20 / state.zoom),
width: this.originIconSize.width,
height: this.originIconSize.height,
});
}
if (locationSettingsState.raw.useGrid.value) {
const activeFowFloor = floorState.currentFloor.value!.id;

Expand All @@ -28,7 +49,6 @@ export class GridLayer extends Layer implements IGridLayer {
this.canvas.style.display = "none";

const ctx = this.ctx;
this.clear();
ctx.beginPath();

const state = positionState.readonly;
Expand Down
33 changes: 25 additions & 8 deletions client/src/game/shapes/variants/fontAwesomeIcon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,33 @@ import type { GlobalId, LocalId } from "../../../core/id";
import type { IAsset } from "../../interfaces/shapes/asset";
import type { SHAPE_TYPE } from "../types";

export type SvgDisplayOverrides = {
fill: string;
stroke: string;
strokeWidth: string;
};

import { Asset } from "./asset";

const faBlobs = new Map<string, string>();

function getFaBlobUrl(iconDef: IconDefinition): string {
const name = `${iconDef.prefix}-${iconDef.iconName}`;
function getFaBlobUrl(
iconDef: IconDefinition,
displayOverrides: SvgDisplayOverrides = { fill: "white", stroke: "black", strokeWidth: "20" },
): string {
const name = `${iconDef.prefix}-${iconDef.iconName}-${displayOverrides.fill}-${displayOverrides.stroke}-${displayOverrides.strokeWidth}`;
if (faBlobs.has(name)) return faBlobs.get(name)!;

const svg = icon(iconDef).node[0] as SVGElement;
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
const path = svg.firstChild as SVGTextPathElement;
path.setAttribute("fill", "white");
path.setAttribute("stroke", "black");
path.setAttribute("stroke-width", "20");
path.setAttribute("fill", displayOverrides.fill);
path.setAttribute("stroke", displayOverrides.stroke);
path.setAttribute("stroke-width", displayOverrides.strokeWidth);
console.log(svg.outerHTML);
const blob = new Blob([svg.outerHTML], { type: "image/svg+xml;charset=utf-8" });
const url = URL.createObjectURL(blob);
console.log(url);
faBlobs.set(name, url);
return url;
}
Expand All @@ -31,13 +43,18 @@ export class FontAwesomeIcon extends Asset implements IAsset {
icon: IconLookup,
topleft: GlobalPoint,
w: number,
options?: { id?: LocalId; uuid?: GlobalId; isSnappable?: boolean; parentId?: LocalId },
options?: {
id?: LocalId;
uuid?: GlobalId;
isSnappable?: boolean;
parentId?: LocalId;
svgDisplayOverrides?: SvgDisplayOverrides;
},
) {
const image = new Image();
const iconDef = findIconDefinition(icon);
const h = w * (iconDef.icon[1] / iconDef.icon[0]);
image.src = getFaBlobUrl(iconDef);

image.src = getFaBlobUrl(iconDef, options?.svgDisplayOverrides);
super(image, topleft, w, h, { isSnappable: false, ...options });
}
}
11 changes: 9 additions & 2 deletions client/src/game/systems/settings/location/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class LocationSettingsSystem implements System {
gridType: this.setGridType.bind(this),
unitSize: this.setUnitSize.bind(this),
unitSizeUnit: this.setUnitSizeUnit.bind(this),
useOriginMarker: this.setUseOriginMarker.bind(this),
dropRatio: this.setDropRatio.bind(this),
fullFow: this.setFullFow.bind(this),
fowLos: this.setFowLos.bind(this),
Expand Down Expand Up @@ -98,8 +99,6 @@ class LocationSettingsSystem implements System {

for (const floor of floorState.raw.floors) {
const gridLayer = floorSystem.getGridLayer(floor)!;
if ($.useGrid.value) gridLayer.canvas.style.display = "block";
else gridLayer.canvas.style.display = "none";
gridLayer.invalidate();
}

Expand Down Expand Up @@ -138,6 +137,14 @@ class LocationSettingsSystem implements System {
if (sync) sendLocationOption("unit_size_unit", unitSizeUnit, location);
}

setUseOriginMarker(useOriginMarker: boolean | undefined, location: number | undefined, sync: boolean): void {
if (!this.setValue($.useOriginMarker, useOriginMarker, location)) return;

floorSystem.invalidateAllFloors();

if (sync) sendLocationOption("use_origin_marker", useOriginMarker, location);
}

setDropRatio(dropRatio: number | undefined, location: number | undefined, sync: boolean): void {
if (!this.setValue($.dropRatio, dropRatio, location)) return;

Expand Down
1 change: 1 addition & 0 deletions client/src/game/systems/settings/location/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface LocationOptions {
gridType: GridType;
unitSize: number;
unitSizeUnit: string;
useOriginMarker: boolean;
fullFow: boolean;
fowOpacity: number;
fowLos: boolean;
Expand Down
1 change: 1 addition & 0 deletions client/src/game/systems/settings/location/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function getInitState(): _S {
useGrid: init(false),
unitSize: init(5), // gridSize computed is not triggering on setDefault for some reason
unitSizeUnit: init("ft"),
useOriginMarker: init(false),
visionMaxRange: init(0),
visionMinRange: init(0),
visionMode: init(""),
Expand Down
9 changes: 9 additions & 0 deletions client/src/game/ui/settings/location/GridSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const gridType = useLocationSettings("gridType", location);

const unitSize = useLocationSettings("unitSize", location);
const unitSizeUnit = useLocationSettings("unitSizeUnit", location);
const useOriginMarker = useLocationSettings("useOriginMarker", location);
const dropRatio = useLocationSettings("dropRatio", location);
</script>

Expand Down Expand Up @@ -69,6 +70,14 @@ const dropRatio = useLocationSettings("dropRatio", location);
<input :id="'unitSizeInput-' + location" v-model.number="unitSize" type="number" step="any" />
</div>
</ResetWrapper>
<ResetWrapper :global="global" :location="location" setting="useOriginMarker">
<label :for="'useOriginMarkerInput-' + location">
{{ t("game.ui.settings.GridSettings.use_origin_marker") }}
</label>
<div>
<input :id="'useOriginMarkerInput-' + location" v-model="useOriginMarker" type="checkbox" />
</div>
</ResetWrapper>
<ResetWrapper :global="global" :location="location" setting="dropRatio">
<div>
<label :for="'dropRatioInput-' + location" :title="t('game.ui.settings.GridSettings.drop_ratio_title')">
Expand Down
1 change: 1 addition & 0 deletions client/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,7 @@
"GridSettings": {
"unit_size_in_UNIT": "Unit Size (in {unit})",
"use_grid": "Use grid",
"use_origin_marker": "Show origin marker",
"size_unit": "Size Unit",
"grid_type": "Grid Type",
"SQUARE": "Squares",
Expand Down
2 changes: 2 additions & 0 deletions server/src/api/models/location/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class ApiLocationOptions(BaseModel):
unit_size: float
unit_size_unit: str
use_grid: bool
use_origin_marker: bool
full_fow: bool
fow_opacity: float
fow_los: bool
Expand All @@ -29,6 +30,7 @@ class ApiOptionalLocationOptions(TypeIdModel):
unit_size: float | None = None
unit_size_unit: str | None = None
use_grid: bool | None = None
use_origin_marker: bool | None = None
full_fow: bool | None = None
fow_opacity: float | None = None
fow_los: bool | None = None
Expand Down
10 changes: 10 additions & 0 deletions server/src/api/socket/location.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class LocationOptionKeys(TypedDict, total=False):
unit_size: float
unit_size_unit: str
use_grid: bool
use_origin_marker: bool
grid_type: str
full_fow: bool
fow_opacity: float
Expand Down Expand Up @@ -297,30 +298,39 @@ async def change_location(sid: str, raw_data: Any):
@sio.on("Location.Options.Set", namespace=GAME_NS)
@auth.login_required(app, sio, "game")
async def set_location_options(sid: str, raw_data: Any):
print("raw_data: " + str(raw_data)) # CRAFTIDEBUG: WARN:
data = LocationOptionsSet(**raw_data)
print("data: " + str(data)) # CRAFTIDEBUG: WARN:

pr: PlayerRoom = game_state.get(sid)

if pr.role != Role.DM:
logger.warning(f"{pr.player.name} attempted to set a room option")
return

print("data.location: " + str(data.location)) # CRAFTIDEBUG: WARN:
if data.location is MISSING:
options = pr.room.default_options
else:
loc = Location.get_by_id(data.location)
print("loc: " + str(loc)) # CRAFTIDEBUG: WARN:
print("loc: " + str(loc.options)) # CRAFTIDEBUG: WARN:
if loc.options is None:
loc.options = LocationOptions.create_empty()
loc.save()
options = loc.options

print("options: " + str(options)) # CRAFTIDEBUG: WARN:
safe_update_model_from_dict(options, raw_data["options"]) # Don't use .model_dump() here
print("new options: " + str(options)) # CRAFTIDEBUG: WARN:
options.save()
print("saved options: " + str(options)) # CRAFTIDEBUG: WARN:

if data.location is MISSING:
for sid in game_state.get_sids(skip_sid=sid, room=pr.room):
await _send_game("Location.Options.Set", raw_data, room=sid)
else:
print("sending data") # CRAFTIDEBUG: WARN:
await _send_game(
"Location.Options.Set",
raw_data,
Expand Down
3 changes: 3 additions & 0 deletions server/src/db/models/location_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class LocationOptions(BaseDbModel):
unit_size = cast(float | None, FloatField(default=5, null=True))
unit_size_unit = cast(str | None, TextField(default="ft", null=True))
use_grid = cast(bool | None, BooleanField(default=True, null=True))
use_origin_marker = cast(bool | None, BooleanField(default=False, null=True))
full_fow = cast(bool | None, BooleanField(default=False, null=True))
fow_opacity = cast(float | None, FloatField(default=0.3, null=True))
fow_los = cast(bool | None, BooleanField(default=False, null=True))
Expand All @@ -35,6 +36,7 @@ def create_empty(cls):
unit_size_unit=None,
grid_type=None,
use_grid=None,
use_origin_marker=None,
full_fow=None,
fow_opacity=None,
fow_los=None,
Expand Down Expand Up @@ -67,6 +69,7 @@ def as_pydantic(self, optional: bool):
unit_size_unit=self.unit_size_unit, # type: ignore
grid_type=self.grid_type, # type: ignore
use_grid=self.use_grid, # type: ignore
use_origin_marker=self.use_origin_marker, # type: ignore
full_fow=self.full_fow, # type: ignore
fow_opacity=self.fow_opacity, # type: ignore
fow_los=self.fow_los, # type: ignore
Expand Down
9 changes: 8 additions & 1 deletion server/src/save.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
- e.g. a column added to Circle also needs to be added to CircularToken
"""

SAVE_VERSION = 113
SAVE_VERSION = 114

import asyncio
import json
Expand Down Expand Up @@ -691,6 +691,13 @@ def upgrade(
db.execute_sql(
'INSERT INTO "text" ("shape_id", "text", "font_size") SELECT "shape_id", "text", "font_size" FROM _text_112'
)
elif version == 113:
# Add use_origin_marker column to location options
with db.atomic():
db.execute_sql("ALTER TABLE location_options ADD COLUMN use_origin_marker INTEGER DEFAULT 0")
db.execute_sql(
"UPDATE location_options SET use_origin_marker = NULL WHERE id NOT IN (SELECT default_options_id FROM room)"
)
else:
raise UnknownVersionException(f"No upgrade code for save format {version} was found.")
inc_save_version(db)
Expand Down
Loading