1 /*
2  * Copyright (c) 2017-2019 sel-project
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  *
22  */
23 /**
24  * Copyright: Copyright (c) 2017-2019 sel-project
25  * License: MIT
26  * Authors: Kripth
27  * Source: $(HTTP github.com/sel-project/selery/source/selery/world/plugin.d, selery/world/plugin.d)
28  */
29 module selery.world.plugin;
30 
31 import std.algorithm : canFind;
32 import std.conv : to;
33 import std.datetime : Duration;
34 import std.traits : hasUDA, getUDAs, Parameters;
35 
36 import selery.about : tick_t;
37 import selery.event.event : CancellableOf;
38 import selery.plugin : event, cancel, command, op, hidden, permissionLevel, permission, unimplemented;
39 import selery.world.world : World;
40 
41 void loadWorld(T:World)(T world, int oldState, uint newState) {
42 
43 	// oldState is -1 and newState is 0 when the world is loaded for the first time
44 
45 	foreach_reverse(member ; __traits(allMembers, T)) {
46 		static if(is(typeof(__traits(getMember, T, member)) == function)) {
47 			mixin("alias F = T." ~ member ~ ";");
48 			static if(hasUDA!(F, task)) {
49 				static assert(getUDAs!(F, task).length == 1);
50 				auto del = mixin("&world." ~ member);
51 				updateSymbols!(getStates!F)(getStates!F, oldState, newState, { world.addTask(del, getUDAs!(F, task)[0].ticks); }, { world.removeTask(del); });
52 			}
53 			static if(hasUDA!(F, command)) {
54 				static assert(getUDAs!(F, command).length == 1);
55 				auto del = mixin("&world." ~ member);
56 				enum c = getUDAs!(F, command)[0];
57 				static if(hasUDA!(F, permissionLevel)) enum pl = getUDAs!(F, permissionLevel)[0].permissionLevel;
58 				else enum ubyte pl = 0;
59 				static if(hasUDA!(F, permission)) enum p = getUDAs!(F, permission)[0].permissions;
60 				else enum string[] p = [];
61 				updateSymbols!(getStates!F)(getStates!F, oldState, newState, { world.registerCommand!F(del, c.command, c.description, c.aliases, pl, p, hasUDA!(F, hidden), !hasUDA!(F, unimplemented)); }, { world.unregisterCommand(c.command); });
62 			}
63 			static if(hasUDA!(F, event)) {
64 				static assert(Parameters!F.length == 1);
65 				static if(hasUDA!(F, cancel)) {
66 					auto del = &CancellableOf.instance.createCancellable!(Parameters!F[0]);
67 				} else {
68 					auto del = mixin("&world." ~ member);
69 				}
70 				updateSymbols!(getStates!F)(getStates!F, oldState, newState, { world.addEventListener(del); }, { world.removeEventListener(del); });
71 			}
72 		}
73 	}
74 
75 }
76 
77 template updateSymbols(uint[] states) {
78 	static if(states.length) alias updateSymbols = updateSymbolsWithStates;
79 	else alias updateSymbols = updateSymbolsWithoutStates;
80 }
81 
82 void updateSymbolsWithStates(uint[] states, int oldState, uint newState, lazy void delegate() add, lazy void delegate() remove) {
83 	immutable bool registered = states.canFind(oldState);
84 	immutable bool needed = states.canFind(newState);
85 	if(registered && !needed) remove()();
86 	else if(needed && !registered) add()();
87 }
88 
89 void updateSymbolsWithoutStates(uint[] states, int oldState, uint newState, lazy void delegate() add, lazy void delegate() remove) {
90 	if(oldState == -1) add()();
91 }
92 
93 uint[] getStates(alias fun)() {
94 	uint[] states;
95 	foreach(s ; getUDAs!(fun, state)) {
96 		states ~= s.states;
97 	}
98 	return states;
99 }
100 
101 struct task {
102 
103 	tick_t ticks;
104 
105 	public this(tick_t ticks) {
106 		assert(ticks != 0);
107 		this.ticks = ticks;
108 	}
109 
110 	public this(Duration duration) {
111 		assert(duration.total!"msecs"() % 50 == 0);
112 		this(to!tick_t(duration.total!"msecs"() / 50));
113 	}
114 
115 }
116 
117 struct state {
118 
119 	private uint[] states;
120 
121 	public this(uint[] states...) {
122 		this.states = states;
123 	}
124 
125 }