Skip to content

Add gamemode and lua support #50

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

Draft
wants to merge 5 commits into
base: develop
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ jobs:
name: apk-x86_64-build
path: app/linwood-setonix-android-x86_64.apk
- name: Copy Corepack
working-directory: ./
run: |
cp app/assets/pack.stnx core.stnx
- name: Archive Corepack
Expand Down
4 changes: 1 addition & 3 deletions api/lib/src/event/process/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -362,9 +362,7 @@ Future<ServerResponse?> processClientEvent(
);
case ModeChangeRequest():
final location = event.location;
final mode = location == null
? null
: assetManager.getPack(location.namespace)?.getMode(location.id);
final mode = location == null ? null : assetManager.getModeItem(location);
return UpdateServerResponse.builder(
WorldInitialized.fromMode(mode, state),
channel,
Expand Down
22 changes: 12 additions & 10 deletions api/lib/src/event/server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,18 @@ final class WorldInitialized extends ServerWorldEvent
this.clearUserInterface = false,
});

factory WorldInitialized.fromMode(GameMode? mode, WorldState state) =>
WorldInitialized(
clearUserInterface: true,
info: state.info.copyWith(
teams: mode?.teams ?? {},
script: mode?.script,
),
table: mode?.tables[state.tableName] ?? GameTable(),
teamMembers: const {},
);
factory WorldInitialized.fromMode(
PackItem<GameMode>? mode,
WorldState state,
) => WorldInitialized(
clearUserInterface: true,
info: state.info.copyWith(
teams: mode?.item.teams ?? {},
script: mode?.location,
),
table: mode?.item.tables[state.tableName] ?? GameTable(),
teamMembers: const {},
);
}

@MappableClass()
Expand Down
8 changes: 8 additions & 0 deletions api/lib/src/models/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ final class SetonixConfig with SetonixConfigMappable {
final String? endpointSecret;
static const String defaultEndpointSecret = '';
static const String envEndpointSecret = 'SETONIX_ENDPOINT_SECRET';
final String? gameMode;
static const String defaultGameMode = '';
static const String envGameMode = 'SETONIX_GAME_MODE';

const SetonixConfig({
this.host,
Expand All @@ -55,6 +58,7 @@ final class SetonixConfig with SetonixConfigMappable {
this.accountRequired,
this.apiEndpoint,
this.endpointSecret,
this.gameMode,
});

static const defaultConfig = SetonixConfig(
Expand All @@ -70,6 +74,7 @@ final class SetonixConfig with SetonixConfigMappable {
accountRequired: defaultAccountRequired,
apiEndpoint: defaultApiEndpoint,
endpointSecret: defaultEndpointSecret,
gameMode: defaultGameMode,
);

static SetonixConfig fromEnvironment() {
Expand Down Expand Up @@ -128,6 +133,9 @@ final class SetonixConfig with SetonixConfigMappable {
defaultValue: defaultEndpointSecret,
)
: null,
gameMode: bool.hasEnvironment(envGameMode)
? String.fromEnvironment(envGameMode, defaultValue: defaultGameMode)
: null,
);
}

Expand Down
12 changes: 12 additions & 0 deletions api/lib/src/models/config.mapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ class SetonixConfigMapper extends ClassMapperBase<SetonixConfig> {
_$endpointSecret,
opt: true,
);
static String? _$gameMode(SetonixConfig v) => v.gameMode;
static const Field<SetonixConfig, String> _f$gameMode = Field(
'gameMode',
_$gameMode,
opt: true,
);

@override
final MappableFields<SetonixConfig> fields = const {
Expand All @@ -107,6 +113,7 @@ class SetonixConfigMapper extends ClassMapperBase<SetonixConfig> {
#accountRequired: _f$accountRequired,
#apiEndpoint: _f$apiEndpoint,
#endpointSecret: _f$endpointSecret,
#gameMode: _f$gameMode,
};

static SetonixConfig _instantiate(DecodingData data) {
Expand All @@ -123,6 +130,7 @@ class SetonixConfigMapper extends ClassMapperBase<SetonixConfig> {
accountRequired: data.dec(_f$accountRequired),
apiEndpoint: data.dec(_f$apiEndpoint),
endpointSecret: data.dec(_f$endpointSecret),
gameMode: data.dec(_f$gameMode),
);
}

Expand Down Expand Up @@ -201,6 +209,7 @@ abstract class SetonixConfigCopyWith<$R, $In extends SetonixConfig, $Out>
bool? accountRequired,
String? apiEndpoint,
String? endpointSecret,
String? gameMode,
});
SetonixConfigCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
Expand All @@ -227,6 +236,7 @@ class _SetonixConfigCopyWithImpl<$R, $Out>
Object? accountRequired = $none,
Object? apiEndpoint = $none,
Object? endpointSecret = $none,
Object? gameMode = $none,
}) => $apply(
FieldCopyWithData({
if (host != $none) #host: host,
Expand All @@ -241,6 +251,7 @@ class _SetonixConfigCopyWithImpl<$R, $Out>
if (accountRequired != $none) #accountRequired: accountRequired,
if (apiEndpoint != $none) #apiEndpoint: apiEndpoint,
if (endpointSecret != $none) #endpointSecret: endpointSecret,
if (gameMode != $none) #gameMode: gameMode,
}),
);
@override
Expand All @@ -257,6 +268,7 @@ class _SetonixConfigCopyWithImpl<$R, $Out>
accountRequired: data.get(#accountRequired, or: $value.accountRequired),
apiEndpoint: data.get(#apiEndpoint, or: $value.apiEndpoint),
endpointSecret: data.get(#endpointSecret, or: $value.endpointSecret),
gameMode: data.get(#gameMode, or: $value.gameMode),
);

@override
Expand Down
24 changes: 24 additions & 0 deletions api/lib/src/models/data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@ class SetonixData extends ArchiveData<SetonixData> {
: identifier = identifier ?? createPackIdentifier(data),
super.fromBytes();

factory SetonixData.fromMode(ItemLocation? location, GameMode? mode) {
var data = SetonixData.empty().setInfo(
GameInfo(
packs: [?location?.namespace],
script: location,
teams: mode?.teams ?? const {},
),
);
for (final entry
in mode?.tables.entries ??
Iterable<MapEntry<String, GameTable>>.empty()) {
data = data.setTable(entry.value, entry.key);
}
return data;
}

GameTable? getTable([String name = '']) {
final data = getAsset('$kGameTablePath/$name.json');
if (data == null) return null;
Expand Down Expand Up @@ -305,6 +321,14 @@ class SetonixData extends ArchiveData<SetonixData> {
}
}

PackItem<GameMode>? getModeItem(String id, [String namespace = '']) =>
PackItem.wrap(
pack: this,
namespace: namespace,
id: id,
item: getMode(id),
);

Map<String, GameMode> getModesData() => Map.fromEntries(
getModes().map((e) {
final mode = getMode(e);
Expand Down
2 changes: 1 addition & 1 deletion api/lib/src/models/info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ part 'info.mapper.dart';
class GameInfo with GameInfoMappable {
final Map<String, GameTeam> teams;
final List<String> packs;
final String? script;
final ItemLocation? script;

const GameInfo({this.teams = const {}, this.packs = const [], this.script});
}
Expand Down
15 changes: 12 additions & 3 deletions api/lib/src/models/info.mapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ class GameInfoMapper extends ClassMapperBase<GameInfo> {
if (_instance == null) {
MapperContainer.globals.use(_instance = GameInfoMapper._());
GameTeamMapper.ensureInitialized();
ItemLocationMapper.ensureInitialized();
}
return _instance!;
}
Expand All @@ -117,8 +118,8 @@ class GameInfoMapper extends ClassMapperBase<GameInfo> {
opt: true,
def: const [],
);
static String? _$script(GameInfo v) => v.script;
static const Field<GameInfo, String> _f$script = Field(
static ItemLocation? _$script(GameInfo v) => v.script;
static const Field<GameInfo, ItemLocation> _f$script = Field(
'script',
_$script,
opt: true,
Expand Down Expand Up @@ -199,7 +200,12 @@ abstract class GameInfoCopyWith<$R, $In extends GameInfo, $Out>
MapCopyWith<$R, String, GameTeam, GameTeamCopyWith<$R, GameTeam, GameTeam>>
get teams;
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get packs;
$R call({Map<String, GameTeam>? teams, List<String>? packs, String? script});
ItemLocationCopyWith<$R, ItemLocation, ItemLocation>? get script;
$R call({
Map<String, GameTeam>? teams,
List<String>? packs,
ItemLocation? script,
});
GameInfoCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}

Expand All @@ -226,6 +232,9 @@ class _GameInfoCopyWithImpl<$R, $Out>
(v) => call(packs: v),
);
@override
ItemLocationCopyWith<$R, ItemLocation, ItemLocation>? get script =>
$value.script?.copyWith.$chain((v) => call(script: v));
@override
$R call({
Map<String, GameTeam>? teams,
List<String>? packs,
Expand Down
2 changes: 0 additions & 2 deletions api/lib/src/models/mode.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,11 @@ final class GameMode with GameModeMappable {
final String? script;

final Map<String, GameTable> tables;
final String tableName;
final Map<String, GameTeam> teams;

GameMode({
required this.script,
this.tables = const {},
this.tableName = '',
this.teams = const {},
});
}
13 changes: 0 additions & 13 deletions api/lib/src/models/mode.mapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,6 @@ class GameModeMapper extends ClassMapperBase<GameMode> {
opt: true,
def: const {},
);
static String _$tableName(GameMode v) => v.tableName;
static const Field<GameMode, String> _f$tableName = Field(
'tableName',
_$tableName,
opt: true,
def: '',
);
static Map<String, GameTeam> _$teams(GameMode v) => v.teams;
static const Field<GameMode, Map<String, GameTeam>> _f$teams = Field(
'teams',
Expand All @@ -50,15 +43,13 @@ class GameModeMapper extends ClassMapperBase<GameMode> {
final MappableFields<GameMode> fields = const {
#script: _f$script,
#tables: _f$tables,
#tableName: _f$tableName,
#teams: _f$teams,
};

static GameMode _instantiate(DecodingData data) {
return GameMode(
script: data.dec(_f$script),
tables: data.dec(_f$tables),
tableName: data.dec(_f$tableName),
teams: data.dec(_f$teams),
);
}
Expand Down Expand Up @@ -132,7 +123,6 @@ abstract class GameModeCopyWith<$R, $In extends GameMode, $Out>
$R call({
String? script,
Map<String, GameTable>? tables,
String? tableName,
Map<String, GameTeam>? teams,
});
GameModeCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
Expand Down Expand Up @@ -169,21 +159,18 @@ class _GameModeCopyWithImpl<$R, $Out>
$R call({
Object? script = $none,
Map<String, GameTable>? tables,
String? tableName,
Map<String, GameTeam>? teams,
}) => $apply(
FieldCopyWithData({
if (script != $none) #script: script,
if (tables != null) #tables: tables,
if (tableName != null) #tableName: tableName,
if (teams != null) #teams: teams,
}),
);
@override
GameMode $make(CopyWithData data) => GameMode(
script: data.get(#script, or: $value.script),
tables: data.get(#tables, or: $value.tables),
tableName: data.get(#tableName, or: $value.tableName),
teams: data.get(#teams, or: $value.teams),
);

Expand Down
28 changes: 27 additions & 1 deletion api/lib/src/models/table.dart
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class BoardTile with BoardTileMappable {
BoardTile(this.asset, this.tile);
}

@MappableClass()
@MappableClass(hook: ItemLocationHook())
class ItemLocation with ItemLocationMappable {
final String namespace, id;

Expand All @@ -130,6 +130,32 @@ class ItemLocation with ItemLocationMappable {
return ItemLocation(splitted[0], splitted[1]);
}

bool get isEmpty => namespace.isEmpty && id.isEmpty;

@override
String toString() => namespace.isEmpty ? id : '$namespace:$id';
}

class ItemLocationHook extends MappingHook {
final bool nullOnEmpty;

const ItemLocationHook({this.nullOnEmpty = true});

@override
Object? beforeDecode(Object? value) {
if (value is String) {
return ItemLocation.fromString(value).toMap();
}
return value;
}

@override
Object? afterEncode(Object? value) {
if (value is ItemLocation) {
if (value.isEmpty && nullOnEmpty) {
return null;
}
}
return value;
}
}
2 changes: 2 additions & 0 deletions api/lib/src/models/table.mapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,8 @@ class ItemLocationMapper extends ClassMapperBase<ItemLocation> {
#id: _f$id,
};

@override
final MappingHook hook = const ItemLocationHook();
static ItemLocation _instantiate(DecodingData data) {
return ItemLocation(data.dec(_f$namespace), data.dec(_f$id));
}
Expand Down
3 changes: 3 additions & 0 deletions api/lib/src/services/asset.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,7 @@ abstract class AssetManager {

PackItem<DeckDefinition>? getDeckItem(ItemLocation location) =>
getPack(location.namespace)?.getDeckItem(location.id, location.namespace);

PackItem<GameMode>? getModeItem(ItemLocation location) =>
getPack(location.namespace)?.getModeItem(location.id, location.namespace);
}
2 changes: 1 addition & 1 deletion api/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: setonix_api
description: The Linwood Setonix API
version: 0.6.0
version: 0.5.1
publish_to: none
# repository: https://github.com/my_org/my_repo

Expand Down
2 changes: 1 addition & 1 deletion app/AppImageBuilder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ AppDir:
id: dev.linwood.setonix
name: Linwood Setonix
icon: dev.linwood.setonix
version: 0.6.0
version: 0.5.1
exec: setonix
exec_args: $@
apt:
Expand Down
6 changes: 3 additions & 3 deletions app/lib/bloc/world/bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,10 @@ class WorldBloc extends Bloc<PlayableWorldEvent, ClientWorldState> {
}
}

Future<void> _loadScript(String? script) async {
Future<void> _loadScript(ItemLocation? location) async {
try {
if (script == null) return;
pluginSystem.loadLuaPlugin(state.assetManager, script);
if (location == null) return;
pluginSystem.loadLuaPluginFromLocation(state.assetManager, location);
// ignore: empty_catches
} catch (e) {}
}
Expand Down
Loading