Skip to content

Commit 4b1752f

Browse files
committed
Add multi world plugin and event system
1 parent 63cd3ad commit 4b1752f

File tree

9 files changed

+139
-122
lines changed

9 files changed

+139
-122
lines changed

api/lib/src/event/event.mapper.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1713,8 +1713,8 @@ mixin ServerStateUpdatedMappable {
17131713

17141714
ServerStateUpdatedCopyWith<ServerStateUpdated, ServerStateUpdated,
17151715
ServerStateUpdated>
1716-
get copyWith => _ServerStateUpdatedCopyWithImpl(
1717-
this as ServerStateUpdated, $identity, $identity);
1716+
get copyWith => _ServerStateUpdatedCopyWithImpl<ServerStateUpdated,
1717+
ServerStateUpdated>(this as ServerStateUpdated, $identity, $identity);
17181718
@override
17191719
String toString() {
17201720
return ServerStateUpdatedMapper.ensureInitialized()
@@ -1737,8 +1737,8 @@ mixin ServerStateUpdatedMappable {
17371737
extension ServerStateUpdatedValueCopy<$R, $Out>
17381738
on ObjectCopyWith<$R, ServerStateUpdated, $Out> {
17391739
ServerStateUpdatedCopyWith<$R, ServerStateUpdated, $Out>
1740-
get $asServerStateUpdated =>
1741-
$base.as((v, t, t2) => _ServerStateUpdatedCopyWithImpl(v, t, t2));
1740+
get $asServerStateUpdated => $base.as(
1741+
(v, t, t2) => _ServerStateUpdatedCopyWithImpl<$R, $Out>(v, t, t2));
17421742
}
17431743

17441744
abstract class ServerStateUpdatedCopyWith<$R, $In extends ServerStateUpdated,
@@ -1771,7 +1771,7 @@ class _ServerStateUpdatedCopyWithImpl<$R, $Out>
17711771
@override
17721772
ServerStateUpdatedCopyWith<$R2, ServerStateUpdated, $Out2> $chain<$R2, $Out2>(
17731773
Then<$Out2, $R2> t) =>
1774-
_ServerStateUpdatedCopyWithImpl($value, $cast, t);
1774+
_ServerStateUpdatedCopyWithImpl<$R2, $Out2>($value, $cast, t);
17751775
}
17761776

17771777
class ClientWorldEventMapper extends SubClassMapperBase<ClientWorldEvent> {

api/lib/src/models/server.mapper.dart

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,8 @@ mixin PlayerInfoMappable {
822822
}
823823

824824
PlayerInfoCopyWith<PlayerInfo, PlayerInfo, PlayerInfo> get copyWith =>
825-
_PlayerInfoCopyWithImpl(this as PlayerInfo, $identity, $identity);
825+
_PlayerInfoCopyWithImpl<PlayerInfo, PlayerInfo>(
826+
this as PlayerInfo, $identity, $identity);
826827
@override
827828
String toString() {
828829
return PlayerInfoMapper.ensureInitialized()
@@ -844,7 +845,7 @@ mixin PlayerInfoMappable {
844845
extension PlayerInfoValueCopy<$R, $Out>
845846
on ObjectCopyWith<$R, PlayerInfo, $Out> {
846847
PlayerInfoCopyWith<$R, PlayerInfo, $Out> get $asPlayerInfo =>
847-
$base.as((v, t, t2) => _PlayerInfoCopyWithImpl(v, t, t2));
848+
$base.as((v, t, t2) => _PlayerInfoCopyWithImpl<$R, $Out>(v, t, t2));
848849
}
849850

850851
abstract class PlayerInfoCopyWith<$R, $In extends PlayerInfo, $Out>
@@ -871,7 +872,7 @@ class _PlayerInfoCopyWithImpl<$R, $Out>
871872
@override
872873
PlayerInfoCopyWith<$R2, PlayerInfo, $Out2> $chain<$R2, $Out2>(
873874
Then<$Out2, $R2> t) =>
874-
_PlayerInfoCopyWithImpl($value, $cast, t);
875+
_PlayerInfoCopyWithImpl<$R2, $Out2>($value, $cast, t);
875876
}
876877

877878
class ServerStateMapper extends ClassMapperBase<ServerState> {
@@ -930,7 +931,8 @@ mixin ServerStateMappable {
930931
}
931932

932933
ServerStateCopyWith<ServerState, ServerState, ServerState> get copyWith =>
933-
_ServerStateCopyWithImpl(this as ServerState, $identity, $identity);
934+
_ServerStateCopyWithImpl<ServerState, ServerState>(
935+
this as ServerState, $identity, $identity);
934936
@override
935937
String toString() {
936938
return ServerStateMapper.ensureInitialized()
@@ -952,7 +954,7 @@ mixin ServerStateMappable {
952954
extension ServerStateValueCopy<$R, $Out>
953955
on ObjectCopyWith<$R, ServerState, $Out> {
954956
ServerStateCopyWith<$R, ServerState, $Out> get $asServerState =>
955-
$base.as((v, t, t2) => _ServerStateCopyWithImpl(v, t, t2));
957+
$base.as((v, t, t2) => _ServerStateCopyWithImpl<$R, $Out>(v, t, t2));
956958
}
957959

958960
abstract class ServerStateCopyWith<$R, $In extends ServerState, $Out>
@@ -989,5 +991,5 @@ class _ServerStateCopyWithImpl<$R, $Out>
989991
@override
990992
ServerStateCopyWith<$R2, ServerState, $Out2> $chain<$R2, $Out2>(
991993
Then<$Out2, $R2> t) =>
992-
_ServerStateCopyWithImpl($value, $cast, t);
994+
_ServerStateCopyWithImpl<$R2, $Out2>($value, $cast, t);
993995
}

app/lib/bloc/world/bloc.dart

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,29 @@ ServerProcessed _compute(
1717

1818
SetonixData _saveState(WorldState state) => state.save();
1919

20+
class _WorldServerInterfaceImpl implements ServerInterface {
21+
final WorldBloc bloc;
22+
23+
_WorldServerInterfaceImpl(this.bloc);
24+
25+
@override
26+
void process(WorldEvent event, {bool force = false, required String plugin}) {
27+
bloc.process(event);
28+
}
29+
30+
@override
31+
void sendEvent(PlayableWorldEvent event,
32+
{Channel target = kAnyChannel, required String plugin}) {
33+
bloc._processEvent(NetworkerPacket(event, target));
34+
}
35+
36+
@override
37+
WorldState get state => bloc.state.world;
38+
39+
@override
40+
List<int> get players => bloc.state.multiplayer.clients.toList();
41+
}
42+
2043
class WorldBloc extends Bloc<PlayableWorldEvent, ClientWorldState> {
2144
late final PluginSystem pluginSystem;
2245
bool _remoteEvent = false;
@@ -41,16 +64,7 @@ class WorldBloc extends Bloc<PlayableWorldEvent, ClientWorldState> {
4164
info: data?.getInfo() ?? const GameInfo(),
4265
),
4366
)) {
44-
pluginSystem = PluginSystem(
45-
onProcess: (p0, p1, [force = false]) {
46-
process(p1);
47-
},
48-
onSendEvent: (packet, worldName) {
49-
_processEvent(packet);
50-
},
51-
playersGetter: () => state.multiplayer.clients.toList(),
52-
stateGetter: () => state.world,
53-
);
67+
pluginSystem = PluginSystem(server: _WorldServerInterfaceImpl(this));
5468
state.multiplayer
5569
..events.listen((event) {
5670
_remoteEvent = true;

plugin/lib/src/plugin.dart

Lines changed: 66 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import 'dart:async';
21
import 'dart:convert';
32
import 'dart:io';
43

@@ -12,49 +11,41 @@ typedef PluginProcessCallback = void Function(String, WorldEvent, [bool force]);
1211
typedef PluginSendEventCallback = void Function(
1312
NetworkerPacket<PlayableWorldEvent> packet, String? worldName);
1413

14+
mixin ServerInterface {
15+
void process(WorldEvent event, {bool force = false, required String plugin});
16+
void sendEvent(PlayableWorldEvent event,
17+
{Channel target = kAnyChannel, required String plugin});
18+
19+
WorldState get state;
20+
List<int> get players;
21+
}
22+
1523
final class PluginSystem {
16-
final Map<
17-
String,
18-
(
19-
SetonixPlugin,
20-
StreamSubscription<ProcessMessage>,
21-
StreamSubscription<SentEvent>
22-
)> _plugins = {};
23-
final PluginProcessCallback _onProcess;
24-
final PluginSendEventCallback _onSendEvent;
25-
final WorldState Function() stateGetter;
26-
final List<int> Function() playersGetter;
24+
final ServerInterface server;
25+
final Map<String, SetonixPlugin> _plugins = {};
2726

2827
PluginSystem({
29-
required PluginProcessCallback onProcess,
30-
required PluginSendEventCallback onSendEvent,
31-
required this.stateGetter,
32-
required this.playersGetter,
33-
}) : _onProcess = onProcess,
34-
_onSendEvent = onSendEvent;
35-
36-
void registerPlugin(String name, SetonixPlugin plugin) {
37-
final processSub = plugin.onProcess
38-
.listen((message) => _onProcess(name, message.event, message.force));
39-
final sendSub = plugin.onSendEvent
40-
.listen((event) => _onSendEvent(event.event, event.worldName));
41-
_plugins[name] = (plugin, processSub, sendSub);
28+
required this.server,
29+
});
30+
31+
SetonixPlugin registerPlugin(String name,
32+
SetonixPlugin Function(PluginServerInterface) pluginBuilder) {
33+
final pluginServer = _PluginServerInterfaceImpl(server, name);
34+
final plugin = pluginBuilder(pluginServer);
35+
return _plugins[name] = plugin;
4236
}
4337

4438
SetonixPlugin registerLuauPlugin(String name, String code,
4539
{void Function(String)? onPrint}) {
4640
if (!_nativeEnabled) throw Exception('Native not enabled');
47-
final plugin = RustSetonixPlugin.build(
48-
(c) => LuauPlugin(code: code, callback: c), this);
49-
registerPlugin(name, plugin);
50-
return plugin;
41+
return registerPlugin(
42+
name,
43+
(pluginServer) => RustSetonixPlugin.build(
44+
(c) => LuauPlugin(code: code, callback: c), pluginServer));
5145
}
5246

5347
void unregisterPlugin(String name) {
54-
final data = _plugins.remove(name);
55-
data?.$1.dispose();
56-
data?.$2.cancel();
57-
data?.$3.cancel();
48+
_plugins.remove(name);
5849
}
5950

6051
void loadLuaPlugin(AssetManager assetManager, String script,
@@ -76,95 +67,104 @@ final class PluginSystem {
7667

7768
void fire(Event event) {
7869
for (final plugin in _plugins.values) {
79-
plugin.$1.eventSystem.fire(event);
70+
plugin.eventSystem.fire(event);
8071
}
8172
}
8273

8374
GameProperty runPing(HttpRequest request, GameProperty property) {
8475
var result = property;
8576
for (final plugin in _plugins.values) {
86-
result = plugin.$1.eventSystem.runPing(request, result);
77+
result = plugin.eventSystem.runPing(request, result);
8778
}
8879
return result;
8980
}
9081

9182
void runLeaveCallback(Channel channel, ConnectionInfo info) {
9283
for (final plugin in _plugins.values) {
93-
plugin.$1.eventSystem.runLeaveCallback(channel, info);
84+
plugin.eventSystem.runLeaveCallback(channel, info);
9485
}
9586
}
9687
}
9788

89+
abstract class PluginServerInterface {
90+
void process(WorldEvent event, {bool force = false});
91+
void sendEvent(PlayableWorldEvent event, {Channel target = kAnyChannel});
92+
WorldState get state;
93+
List<int> get players;
94+
}
95+
96+
class _PluginServerInterfaceImpl implements PluginServerInterface {
97+
final ServerInterface server;
98+
final String pluginName;
99+
100+
_PluginServerInterfaceImpl(this.server, this.pluginName);
101+
102+
@override
103+
void process(WorldEvent event, {bool force = false}) {
104+
server.process(event, force: force, plugin: pluginName);
105+
}
106+
107+
@override
108+
void sendEvent(PlayableWorldEvent event, {Channel target = kAnyChannel}) {
109+
server.sendEvent(event, target: target, plugin: pluginName);
110+
}
111+
112+
@override
113+
WorldState get state => server.state;
114+
115+
@override
116+
List<int> get players => server.players;
117+
}
118+
98119
final class ProcessMessage {
99120
final WorldEvent event;
100121
final bool force;
101122

102123
ProcessMessage(this.event, this.force);
103124
}
104125

105-
final class SentEvent {
106-
final NetworkerPacket<PlayableWorldEvent> event;
107-
final String? worldName;
108-
109-
SentEvent(this.event, [this.worldName]);
110-
}
111-
112126
class SetonixPlugin {
127+
final PluginServerInterface server;
113128
final EventSystem eventSystem = EventSystem();
114-
final StreamController<ProcessMessage> _onProcessController =
115-
StreamController.broadcast();
116-
final StreamController<SentEvent> _onSendEventController =
117-
StreamController.broadcast();
118129

119-
Stream<ProcessMessage> get onProcess => _onProcessController.stream;
120-
Stream<SentEvent> get onSendEvent => _onSendEventController.stream;
121-
122-
void process(WorldEvent event, {bool force = false}) =>
123-
_onProcessController.add(ProcessMessage(event, force));
124-
125-
void sendEvent(PlayableWorldEvent event,
126-
{Channel target = kAnyChannel, String? worldName}) =>
127-
_onSendEventController
128-
.add(SentEvent(NetworkerPacket(event, target), worldName));
130+
SetonixPlugin(this.server);
129131

130132
void dispose() {
131133
eventSystem.dispose();
132-
_onProcessController.close();
133-
_onSendEventController.close();
134134
}
135135
}
136136

137137
final class RustSetonixPlugin extends SetonixPlugin {
138138
final RustPlugin plugin;
139139

140-
RustSetonixPlugin._(this.plugin);
140+
RustSetonixPlugin._(super.server, this.plugin);
141141

142142
factory RustSetonixPlugin.build(
143143
RustPlugin Function(PluginCallback) builder,
144-
PluginSystem pluginSystem, {
144+
PluginServerInterface server, {
145145
void Function(String)? onPrint,
146146
}) {
147147
final callback = PluginCallback.default_();
148148
final plugin = builder(callback);
149-
final instance = RustSetonixPlugin._(plugin);
149+
final instance = RustSetonixPlugin._(server, plugin);
150150
if (onPrint != null) {
151151
callback.changeOnPrint(onPrint: onPrint);
152152
}
153153
callback.changeProcessEvent(processEvent: (eventSerizalized, force) {
154154
final event = WorldEventMapper.fromJson(eventSerizalized);
155-
instance.process(event, force: force ?? false);
155+
server.process(event, force: force ?? false);
156156
});
157157
callback.changeSendEvent(sendEvent: (eventSerizalized, target) {
158158
final event = PlayableWorldEventMapper.fromJson(eventSerizalized);
159-
instance.sendEvent(event, target: target ?? kAnyChannel);
159+
server.sendEvent(event, target: target ?? kAnyChannel);
160160
});
161161
callback.changeStateFieldAccess(stateFieldAccess: (field) {
162-
final state = pluginSystem.stateGetter();
162+
final state = server.state;
163163
return switch (field) {
164164
StateFieldAccess.info => state.info.toJson(),
165165
StateFieldAccess.table => state.table.toJson(),
166166
StateFieldAccess.tableName => jsonEncode(state.tableName),
167-
StateFieldAccess.players => jsonEncode(pluginSystem.playersGetter()),
167+
StateFieldAccess.players => jsonEncode(server.players),
168168
StateFieldAccess.teamMembers => jsonEncode(state.teamMembers),
169169
};
170170
});

server/example/dialog.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ Future<void> onLoad(SetonixServer server) async {
4444
print("on load was called");
4545
final image = await File("../app/images/logo.png").readAsBytes();
4646
server.process(ImagesUpdated.single('logo', image));
47-
server.eventSystem
47+
server.defaultEventSystem
4848
..on<ObjectsMoved>((e) {
4949
print("Listener was called, opening dialog");
5050
server.sendEvent(DialogOpened(

server/example/duplicate.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ Future<void> onLoad(SetonixServer server) async {
99
// Add your custom code here
1010
bool toggleCancel = false;
1111
// Put the event you want to listen to in the brackets
12-
server.eventSystem.on<ObjectsMoved>((e) {
12+
server.defaultEventSystem.on<ObjectsMoved>((e) {
1313
print("Listener was called, cancel: $toggleCancel");
1414
// Cancel the event every second time and duplicate the objects instead
1515
if (toggleCancel) {
1616
final event = e.clientEvent;
17-
final table = server.state.getTableOrDefault(event.table);
17+
final table = server.defaultState.getTableOrDefault(event.table);
1818
final cell = table.getCell(event.from);
1919
final objects = <GameObject>[];
2020
for (final index in event.objects) {

server/example/join.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Future<void> main(List<String> arguments) {
66

77
Future<void> onLoad(SetonixServer server) async {
88
print("on load was called");
9-
server.eventSystem
9+
server.defaultEventSystem
1010
..on<UserJoined>((e) {
1111
server.sendEvent(DialogOpened(GameDialog(
1212
id: "joinDialog",

0 commit comments

Comments
 (0)