Skip to content
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

Feature/plugin system #43

Merged
merged 23 commits into from
Mar 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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
32 changes: 27 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -205,12 +205,14 @@ jobs:
cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:'
cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:'
- name: ✅ Enable platforms
run: flutter config --enable-linux-desktop
run: |
rm -f "$(dirname "$(dirname "$(command -v flutter)")")/engine/src/.gn"
flutter config --enable-linux-desktop
- name: 📦 Get dependencies
run: |
flutter clean
flutter pub get
flutter doctor -v
flutter pub get
- name: Build nessesary files
working-directory: ./
run: |
Expand All @@ -231,6 +233,10 @@ jobs:
- name: 🏭 Make binary executable
run: |
chmod +x build/linux/${{ matrix.arch.dir }}/release/bundle/setonix
- name: Update files to arm64
if: ${{ matrix.arch.name == 'arm64' }}
run: |
sed -i 's/^Architecture: amd64/Architecture: arm64/' linux/debian/DEBIAN/control
- name: Build .deb executable
run: |
cp -fr build/linux/${{ matrix.arch.dir }}/release/bundle linux/debian/usr/bin
Expand Down Expand Up @@ -335,7 +341,9 @@ jobs:
cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:'
cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:'
- name: ✅ Enable platforms
run: flutter config --enable-linux-desktop
run: |
rm -f "$(dirname "$(dirname "$(command -v flutter)")")/engine/src/.gn"
flutter config --enable-linux-desktop
- name: 📦 Get dependencies
run: |
flutter clean
Expand Down Expand Up @@ -519,12 +527,16 @@ jobs:
os:
- name: ubuntu-24.04
label: linux-x86_64
rust: libsetonix_plugin.so
- name: ubuntu-24.04-arm
label: linux-arm64
rust: libsetonix_plugin.so
- name: windows-2025
label: windows-x86_64
rust: setonix_plugin.dll
- name: macos-latest
label: macos
rust: libsetonix_plugin.dylib
runs-on: ${{ matrix.os.name }}
steps:
- name: ⬆️ Checkout
Expand All @@ -544,6 +556,10 @@ jobs:
flutter clean
flutter pub get
flutter doctor -v
- name: Compile rust
working-directory: plugin/rust
run: |
cargo build --release
- name: Compile
run: |
dart compile exe bin/setonix_server.dart
Expand All @@ -552,6 +568,10 @@ jobs:
mkdir -p server-build
mv bin/setonix_server.exe server-build/
mkdir -p server-build/packs
- name: Move rust lib
working-directory: ./
run: |
cp plugin/rust/target/release/${{ matrix.os.rust }} server/server-build/
- name: Build nessesary files
working-directory: ./
run: |
Expand Down Expand Up @@ -676,7 +696,9 @@ jobs:
path: server-build-macos/
- name: 📦 Zip artifacts
run: |
zip -r linwood-setonix-windows-x86_64.zip windows-build/*
cd windows-build
zip -r ../linwood-setonix-windows-x86_64.zip *
cd ..
tar -C linux-x86_64-build -czf linwood-setonix-linux-x86_64.tar.gz .
tar -C linux-arm64-build -czf linwood-setonix-linux-arm64.tar.gz .
zip -r linwood-setonix-server-windows-x86_64.zip server-build-windows-x86_64/*
Expand Down Expand Up @@ -855,7 +877,7 @@ jobs:
- name: Setup Fastlane
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.3.6"
ruby-version: "3.3.7"
bundler-cache: true
working-directory: app/android
- name: 🚀 Deploy to Play Store
Expand Down
14 changes: 13 additions & 1 deletion .github/workflows/dart.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
continue-on-error: true
strategy:
matrix:
projects: [app, api, server, tools]
projects: [app, api, plugin, server, tools]
defaults:
run:
working-directory: ${{ matrix.projects }}
Expand All @@ -33,13 +33,25 @@ jobs:
- name: Install dependencies
run: |
flutter pub get
- name: Install app specific dependencies
if: matrix.projects == 'app'
run: |
cd rust_builder
flutter pub get
cd cargokit/build_tool
flutter pub get
# Uncomment this step to verify the use of 'dart format' on each commit.
- name: Verify formatting
run: dart format --output=none --set-exit-if-changed .
# Consider passing '--fatal-infos' for slightly stricter analysis.
- name: Analyze project source
run: |
flutter analyze --fatal-infos
- name: Build flutter_rust_bridge bindings
if: matrix.projects == 'plugin'
run: |
cargo install [email protected]
flutter_rust_bridge_codegen generate
- name: Run build_runner
if: matrix.projects == 'api' || matrix.projects == 'app'
run: dart run build_runner build --delete-conflicting-outputs
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ jobs:
echo '' >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV
- name: Discord Webhook Action
uses: tsickert/discord-webhook@v6.0.0
uses: tsickert/discord-webhook@v7.0.0
if: ${{ github.event.inputs.stable == 'true' || github.ref == 'refs/heads/main' }}
with:
webhook-url: ${{ secrets.WEBHOOK_URL }}
Expand All @@ -243,7 +243,7 @@ jobs:
Download it here: https://setonix.world/downloads
https://github.com/LinwoodDev/Setonix/releases/tag/v${{ env.SETONIX_VERSION }}
- name: Discord Webhook Action
uses: tsickert/discord-webhook@v6.0.0
uses: tsickert/discord-webhook@v7.0.0
if: ${{ github.event.inputs.stable == 'false' && github.ref == 'refs/heads/develop' }}
with:
webhook-url: ${{ secrets.WEBHOOK_URL }}
Expand Down
1 change: 1 addition & 0 deletions api/lib/models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export 'src/models/definition.dart';
export 'src/models/dialog.dart';
export 'src/models/info.dart';
export 'src/models/meta.dart';
export 'src/models/mode.dart';
export 'src/models/server.dart';
export 'src/models/table.dart';
export 'src/models/translation.dart';
Expand Down
9 changes: 9 additions & 0 deletions api/lib/src/event/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,12 @@ final class ImagesRequest extends ClientWorldEvent with ImagesRequestMappable {

ImagesRequest(this.ids);
}

@MappableClass()
final class ModeChangeRequest extends ClientWorldEvent
with ModeChangeRequestMappable {
final ItemLocation? location;

ModeChangeRequest(this.location);
ModeChangeRequest.plain() : location = null;
}
144 changes: 139 additions & 5 deletions api/lib/src/event/event.mapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,9 @@ class WorldInitializedMapper extends SubClassMapperBase<WorldInitialized> {
v.packsSignature;
static const Field<WorldInitialized, List<SignatureMetadata>>
_f$packsSignature = Field('packsSignature', _$packsSignature, opt: true);
static bool _$clearUserInterface(WorldInitialized v) => v.clearUserInterface;
static const Field<WorldInitialized, bool> _f$clearUserInterface =
Field('clearUserInterface', _$clearUserInterface, opt: true, def: false);

@override
final MappableFields<WorldInitialized> fields = const {
Expand All @@ -228,6 +231,7 @@ class WorldInitializedMapper extends SubClassMapperBase<WorldInitialized> {
#teamMembers: _f$teamMembers,
#id: _f$id,
#packsSignature: _f$packsSignature,
#clearUserInterface: _f$clearUserInterface,
};

@override
Expand All @@ -244,7 +248,8 @@ class WorldInitializedMapper extends SubClassMapperBase<WorldInitialized> {
info: data.dec(_f$info),
teamMembers: data.dec(_f$teamMembers),
id: data.dec(_f$id),
packsSignature: data.dec(_f$packsSignature));
packsSignature: data.dec(_f$packsSignature),
clearUserInterface: data.dec(_f$clearUserInterface));
}

@override
Expand Down Expand Up @@ -314,7 +319,8 @@ abstract class WorldInitializedCopyWith<$R, $In extends WorldInitialized, $Out>
GameInfo? info,
Map<String, Set<int>>? teamMembers,
int? id,
List<SignatureMetadata>? packsSignature});
List<SignatureMetadata>? packsSignature,
bool? clearUserInterface});
WorldInitializedCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t);
}
Expand Down Expand Up @@ -354,21 +360,25 @@ class _WorldInitializedCopyWithImpl<$R, $Out>
Object? info = $none,
Object? teamMembers = $none,
Object? id = $none,
Object? packsSignature = $none}) =>
Object? packsSignature = $none,
bool? clearUserInterface}) =>
$apply(FieldCopyWithData({
if (table != $none) #table: table,
if (info != $none) #info: info,
if (teamMembers != $none) #teamMembers: teamMembers,
if (id != $none) #id: id,
if (packsSignature != $none) #packsSignature: packsSignature
if (packsSignature != $none) #packsSignature: packsSignature,
if (clearUserInterface != null) #clearUserInterface: clearUserInterface
}));
@override
WorldInitialized $make(CopyWithData data) => WorldInitialized(
table: data.get(#table, or: $value.table),
info: data.get(#info, or: $value.info),
teamMembers: data.get(#teamMembers, or: $value.teamMembers),
id: data.get(#id, or: $value.id),
packsSignature: data.get(#packsSignature, or: $value.packsSignature));
packsSignature: data.get(#packsSignature, or: $value.packsSignature),
clearUserInterface:
data.get(#clearUserInterface, or: $value.clearUserInterface));

@override
WorldInitializedCopyWith<$R2, WorldInitialized, $Out2> $chain<$R2, $Out2>(
Expand Down Expand Up @@ -1650,6 +1660,7 @@ class ClientWorldEventMapper extends SubClassMapperBase<ClientWorldEvent> {
BoardMoveRequestMapper.ensureInitialized();
DialogCloseRequestMapper.ensureInitialized();
ImagesRequestMapper.ensureInitialized();
ModeChangeRequestMapper.ensureInitialized();
HybridWorldEventMapper.ensureInitialized();
}
return _instance!;
Expand Down Expand Up @@ -3095,6 +3106,129 @@ class _ImagesRequestCopyWithImpl<$R, $Out>
_ImagesRequestCopyWithImpl($value, $cast, t);
}

class ModeChangeRequestMapper extends SubClassMapperBase<ModeChangeRequest> {
ModeChangeRequestMapper._();

static ModeChangeRequestMapper? _instance;
static ModeChangeRequestMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = ModeChangeRequestMapper._());
ClientWorldEventMapper.ensureInitialized().addSubMapper(_instance!);
ItemLocationMapper.ensureInitialized();
}
return _instance!;
}

@override
final String id = 'ModeChangeRequest';

static ItemLocation? _$location(ModeChangeRequest v) => v.location;
static const Field<ModeChangeRequest, ItemLocation> _f$location =
Field('location', _$location);

@override
final MappableFields<ModeChangeRequest> fields = const {
#location: _f$location,
};

@override
final String discriminatorKey = 'type';
@override
final dynamic discriminatorValue = 'ModeChangeRequest';
@override
late final ClassMapperBase superMapper =
ClientWorldEventMapper.ensureInitialized();

static ModeChangeRequest _instantiate(DecodingData data) {
return ModeChangeRequest(data.dec(_f$location));
}

@override
final Function instantiate = _instantiate;

static ModeChangeRequest fromMap(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<ModeChangeRequest>(map);
}

static ModeChangeRequest fromJson(String json) {
return ensureInitialized().decodeJson<ModeChangeRequest>(json);
}
}

mixin ModeChangeRequestMappable {
String toJson() {
return ModeChangeRequestMapper.ensureInitialized()
.encodeJson<ModeChangeRequest>(this as ModeChangeRequest);
}

Map<String, dynamic> toMap() {
return ModeChangeRequestMapper.ensureInitialized()
.encodeMap<ModeChangeRequest>(this as ModeChangeRequest);
}

ModeChangeRequestCopyWith<ModeChangeRequest, ModeChangeRequest,
ModeChangeRequest>
get copyWith => _ModeChangeRequestCopyWithImpl(
this as ModeChangeRequest, $identity, $identity);
@override
String toString() {
return ModeChangeRequestMapper.ensureInitialized()
.stringifyValue(this as ModeChangeRequest);
}

@override
bool operator ==(Object other) {
return ModeChangeRequestMapper.ensureInitialized()
.equalsValue(this as ModeChangeRequest, other);
}

@override
int get hashCode {
return ModeChangeRequestMapper.ensureInitialized()
.hashValue(this as ModeChangeRequest);
}
}

extension ModeChangeRequestValueCopy<$R, $Out>
on ObjectCopyWith<$R, ModeChangeRequest, $Out> {
ModeChangeRequestCopyWith<$R, ModeChangeRequest, $Out>
get $asModeChangeRequest =>
$base.as((v, t, t2) => _ModeChangeRequestCopyWithImpl(v, t, t2));
}

abstract class ModeChangeRequestCopyWith<$R, $In extends ModeChangeRequest,
$Out> implements ClientWorldEventCopyWith<$R, $In, $Out> {
ItemLocationCopyWith<$R, ItemLocation, ItemLocation>? get location;
@override
$R call({ItemLocation? location});
ModeChangeRequestCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t);
}

class _ModeChangeRequestCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, ModeChangeRequest, $Out>
implements ModeChangeRequestCopyWith<$R, ModeChangeRequest, $Out> {
_ModeChangeRequestCopyWithImpl(super.value, super.then, super.then2);

@override
late final ClassMapperBase<ModeChangeRequest> $mapper =
ModeChangeRequestMapper.ensureInitialized();
@override
ItemLocationCopyWith<$R, ItemLocation, ItemLocation>? get location =>
$value.location?.copyWith.$chain((v) => call(location: v));
@override
$R call({Object? location = $none}) =>
$apply(FieldCopyWithData({if (location != $none) #location: location}));
@override
ModeChangeRequest $make(CopyWithData data) =>
ModeChangeRequest(data.get(#location, or: $value.location));

@override
ModeChangeRequestCopyWith<$R2, ModeChangeRequest, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_ModeChangeRequestCopyWithImpl($value, $cast, t);
}

class HybridWorldEventMapper extends SubClassMapperBase<HybridWorldEvent> {
HybridWorldEventMapper._();

Expand Down
8 changes: 8 additions & 0 deletions api/lib/src/event/process/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ bool isValidClientEvent(
.tiles
.length -
1),
ModeChangeRequest() => channel == kAuthorityChannel,
_ => true,
};

Expand Down Expand Up @@ -271,5 +272,12 @@ ServerResponse? processClientEvent(
return MapEntry(e, image);
}).nonNulls)),
channel);
case ModeChangeRequest():
final location = event.location;
final mode = location == null
? null
: assetManager.getPack(location.namespace)?.getMode(location.id);
return ServerResponse.builder(
WorldInitialized.fromMode(mode, state), channel);
}
}
Loading