1 /* coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, version 3 of the License ONLY.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 import mesengine
: Loc
, TypeBase
, TypeEnum
, typeBool
, typeInt
, typeActor
;
25 // ////////////////////////////////////////////////////////////////////////// //
26 public struct ActorId
{
27 uint id
; // 0: empty; low word is index, high word is counter
28 @property bool empty () const pure nothrow @safe @nogc { pragma(inline
, true); return ((id
&0xffff) == 0); }
29 @property bool alive () const nothrow @trusted @nogc { pragma(inline
, true); return ((id
&0xffff) > 0 && (id
&0xffff) < actors
.length
&& id
== actors
.ptr
[id
&0xffff][0]); }
31 // this is how MES does it
32 //@property bool opCast(T) () const nothrow @safe @nogc if (is(T == bool)) { pragma(inline, true); return (id != 0); }
36 public struct ActorField
{
42 @property bool valid () const pure nothrow @safe @nogc { pragma(inline
, true); return (type
!is null); }
46 // ////////////////////////////////////////////////////////////////////////// //
47 __gshared
int[][] actors
; // first is always index; if bit 15 is set, this slot is free
48 __gshared
int[string
] actfields
; // in actfieldlist
49 __gshared ActorField
[] actfieldlist
;
50 __gshared
int actfieldsused
= 1; // cells
51 __gshared
int aliveActorCount
= 0;
54 // ////////////////////////////////////////////////////////////////////////// //
55 public int NumObjects () nothrow @trusted @nogc { pragma(inline
, true); return aliveActorCount
; }
58 // ////////////////////////////////////////////////////////////////////////// //
59 public int[] actorGetById() (in ActorId aid
) nothrow @trusted @nogc {
61 return (aid
.alive ? actors
.ptr
[aid
.id
&0xffff] : null);
65 public int[] actorGetByIndex() (in int idx
) nothrow @trusted @nogc {
67 return (idx
>= 0 && idx
< actors
.length
&& (actors
.ptr
[idx
].ptr
[0]&0x8000) == 0 ? actors
.ptr
[idx
] : null);
71 public ActorField
actorFindField (const(char)[] name
) {
72 if (auto aip
= name
in actfields
) return actfieldlist
[*aip
];
73 return ActorField
.init
;
76 public ActorField
* actorFindFieldPtr (const(char)[] name
) {
77 if (auto aip
= name
in actfields
) return &actfieldlist
[*aip
];
82 public ActorField
actorCreateField(T
:const(char)[]) (T name
, TypeBase atype
, in auto ref Loc loc
) {
83 assert(atype
!is null);
84 assert(atype
.cellSize
> 0);
86 if (auto aip
= name
in actfields
) {
87 if (actfieldlist
[*aip
].type
.same(atype
)) return actfieldlist
[*aip
];
88 return ActorField
.init
;
92 af
.ofs
= actfieldsused
;
94 static if (is(T
== string
)) af
.name
= name
; else af
.name
= name
.idup
;
95 actfieldsused
+= atype
.cellSize
;
96 auto aidx
= cast(int)actfieldlist
.length
;
98 actfields
[af
.name
] = aidx
;
103 // ////////////////////////////////////////////////////////////////////////// //
104 public ActorId
spawnActor () {
105 // no actors, create actor pool
106 if (actors
.length
== 0) {
108 actors
.reserve(32768);
109 actors
.length
= 80; // arbitrary number
110 foreach (immutable idx
, ref int[] aa
; actors
) {
111 aa
= new int[](actfieldsused
);
113 aa
[0] = (cast(int)idx
)|
0x8000; // "free flag"
115 actors
[0][0] = 0xffff_0000; // just in case
117 //TODO: use some kind of list or hash table instead of linear search
118 foreach (immutable idx
, int[] aa
; actors
) {
119 if (idx
&& (aa
.ptr
[0]&0x8000) != 0) {
120 if ((aa
.ptr
[0]>>16) == 0xffff) aa
.ptr
[0] &= 0xffff; else aa
.ptr
[0] += 0x0001_0000;
121 aa
.ptr
[0] &= 0xffff_7fff; // clear "free" flag
122 aa
[1..$] = 0; // clear instance
124 return ActorId(aa
[0]);
128 if (actors
.length
>= ushort.max
/2-1) throw new Exception("too many alive actors");
129 int[] aa
= new int[](actfieldsused
);
132 aa
[0] = (cast(int)actors
.length
)|
0x0001_0000;
135 return ActorId(aa
[0]);
139 // mark actor as dead
140 public void killActor (ActorId aid
) nothrow @trusted @nogc {
142 assert(aliveActorCount
> 0);
143 int[] aa
= actors
.ptr
[aid
.id
&0xffff];
144 assert(aa
.length
> 0);
145 assert((aa
.ptr
[0]&0x8000) == 0);
152 // move all alive actors to top, reset indicies
153 public void actorsPack () {
155 foreach (immutable aidx
, int[] aa
; actors
) {
156 if (aidx
== 0) continue;
157 if ((aa
.ptr
[0]&0x8000) != 0) {
159 aa
[0] = cast(int)aidx|
0x8000; // "free flag"
162 // move alive actor to top
163 assert(dpos
<= aidx
);
164 aa
[0] = dpos|
0x0001; // reset index
166 actors
.ptr
[dpos
][] = aa
[]; // move data
167 aa
[0] = cast(int)aidx|
0x8000; // "free flag"
171 assert(dpos
-1 == aliveActorCount
);
172 if (actors
.length
> 80 && dpos
< 80) {
174 actors
.assumeSafeAppend
;
179 public void actorsGC () {
180 int lastUsedActor
= 0;
181 foreach (immutable aidx
, int[] aa
; actors
) {
182 if (aidx
== 0 ||
(aa
.ptr
[0]&0x8000) != 0) continue;
183 lastUsedActor
= cast(int)aidx
;
185 if (actors
.length
> 80 && lastUsedActor
< 80) {
187 actors
.assumeSafeAppend
;
192 // ////////////////////////////////////////////////////////////////////////// //
193 // must return `ActorId.init` when there are no more actors to iterate
194 public ActorId
actorIterStart () nothrow @trusted @nogc {
195 foreach (immutable aidx
, int[] aa
; actors
) {
196 if (aidx
== 0 ||
(aa
.ptr
[0]&0x8000) != 0) continue;
197 return ActorId(aa
.ptr
[0]);
203 // must return `ActorId.init` when there are no more actors to iterate
204 public ActorId
actorIterNext (ActorId aid
) nothrow @trusted @nogc {
205 if (aid
.empty
) return ActorId
.init
;
206 int aidx
= cast(int)(aid
.id
&0xffff)+1;
207 while (aidx
< actors
.length
&& (actors
.ptr
[aidx
].ptr
[0]&0x8000) != 0) ++aidx
;
208 if (aidx
>= actors
.length
) return ActorId
.init
;
209 return ActorId(actors
.ptr
[aidx
].ptr
[0]);