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 }