1+ use crate :: dungeon:: dungeon:: { Dungeon , DungeonState } ;
2+ use crate :: dungeon:: room:: room:: Room ;
3+ use crate :: dungeon:: room:: room_implementation:: RoomImplementation ;
4+ use crate :: dungeon:: seeded_rng:: { seeded_rng, SeededRng } ;
5+ use glam:: { dvec3, ivec3, IVec3 } ;
6+ use rand:: prelude:: SliceRandom ;
7+ use rand:: Rng ;
8+ use server:: block:: rotatable:: Rotate ;
9+ use server:: network:: protocol:: play:: clientbound:: PositionLook ;
10+ use server:: types:: aabb:: AABB ;
11+ use server:: World ;
12+
13+ pub struct TeleportMaze {
14+ teleport_pads : Vec < TeleportPad > ,
15+ target : IVec3 ,
16+ }
17+
18+ struct TeleportPad {
19+ position : IVec3 ,
20+ teleports_to : IVec3 ,
21+ rotate_type : TeleportPadRotation ,
22+ }
23+
24+ enum TeleportPadRotation {
25+ Static { yaw : f32 } ,
26+ TowardsEnd
27+ }
28+
29+ impl TeleportPad {
30+ pub fn aabb ( & self ) -> AABB {
31+ let position = self . position . as_dvec3 ( ) ;
32+ AABB :: new ( position, position + dvec3 ( 1.0 , 0.1 , 1.0 ) )
33+ }
34+ }
35+
36+ impl Default for TeleportMaze {
37+ fn default ( ) -> Self {
38+ let mut teleport_pads: Vec < TeleportPad > = Vec :: new ( ) ;
39+
40+ // not the prettiest
41+ let rng = & mut seeded_rng ( ) ;
42+ let mut sections: Vec < Vec < ( IVec3 , IVec3 ) > > = Vec :: new ( ) ;
43+
44+ for index in 0 ..7 {
45+ let offset = match index {
46+ 0 => ivec3 ( 20 , 70 , 6 ) ,
47+ 1 => ivec3 ( 20 , 70 , 14 ) ,
48+ 2 => ivec3 ( 20 , 70 , 22 ) ,
49+ 3 => ivec3 ( 12 , 70 , 22 ) ,
50+ 4 => ivec3 ( 4 , 70 , 22 ) ,
51+ 5 => ivec3 ( 4 , 70 , 14 ) ,
52+ 6 => ivec3 ( 4 , 70 , 6 ) ,
53+ _ => unreachable ! ( )
54+ } ;
55+ sections. push ( vec ! [
56+ ( offset, offset + ivec3( 1 , -1 , 1 ) ) ,
57+ ( offset + ivec3( 6 , 0 , 0 ) , offset + ivec3( 5 , -1 , 1 ) ) ,
58+ ( offset + ivec3( 0 , 0 , 6 ) , offset + ivec3( 1 , -1 , 5 ) ) ,
59+ ( offset + ivec3( 6 , 0 , 6 ) , offset + ivec3( 5 , -1 , 5 ) ) ,
60+ ] ) ;
61+ }
62+
63+ sections. shuffle ( rng) ;
64+
65+ const ENTRANCE_PAD : IVec3 = ivec3 ( 15 , 70 , 12 ) ;
66+ const EXIT_PAD : IVec3 = ivec3 ( 15 , 70 , 14 ) ;
67+ const ENTRANCE_PAD_TO : IVec3 = ivec3 ( 15 , 69 , 11 ) ;
68+ const EXIT_PAD_TO : IVec3 = ivec3 ( 15 , 69 , 15 ) ;
69+
70+ // entrance
71+ let pads = & mut sections[ 0 ] ;
72+ let ( pad, to_pad) = pop_with_rng ( pads, rng) ;
73+
74+ teleport_pads. push ( TeleportPad {
75+ position : ENTRANCE_PAD ,
76+ teleports_to : to_pad,
77+ rotate_type : TeleportPadRotation :: TowardsEnd ,
78+ } ) ;
79+ teleport_pads. push ( TeleportPad {
80+ position : pad,
81+ teleports_to : ENTRANCE_PAD_TO ,
82+ rotate_type : TeleportPadRotation :: Static { yaw : 180.0 } ,
83+ } ) ;
84+
85+ // exit
86+ let pads = & mut sections[ 6 ] ;
87+ let ( pad_leading_to_end, _) = pop_with_rng ( pads, rng) ;
88+
89+ teleport_pads. push ( TeleportPad {
90+ position : pad_leading_to_end,
91+ teleports_to : EXIT_PAD_TO ,
92+ rotate_type : TeleportPadRotation :: Static { yaw : 0.0 } ,
93+ } ) ;
94+ teleport_pads. push ( TeleportPad {
95+ position : EXIT_PAD ,
96+ teleports_to : ENTRANCE_PAD_TO ,
97+ rotate_type : TeleportPadRotation :: Static { yaw : 180.0 } ,
98+ } ) ;
99+
100+ // this makes sure every section is able to be travelled to
101+ for index in 0 ..6 {
102+ let section_a = & mut sections[ index] ;
103+ let ( pad_a, to_pad_a) = pop_with_rng ( section_a, rng) ;
104+ let section_b = & mut sections[ index + 1 ] ;
105+ let ( pad_b, to_pad_b) = pop_with_rng ( section_b, rng) ;
106+
107+ teleport_pads. push ( TeleportPad {
108+ position : pad_a,
109+ teleports_to : to_pad_b,
110+ rotate_type : TeleportPadRotation :: TowardsEnd ,
111+ } ) ;
112+ teleport_pads. push ( TeleportPad {
113+ position : pad_b,
114+ teleports_to : to_pad_a,
115+ rotate_type : TeleportPadRotation :: TowardsEnd ,
116+ } ) ;
117+ }
118+
119+ let mut remaining: Vec < ( usize , IVec3 , IVec3 ) > = sections
120+ . iter ( )
121+ . enumerate ( )
122+ . flat_map ( |( section_idx, pads) | {
123+ pads. iter ( ) . map ( move |& ( pad, to_pad) | ( section_idx, pad, to_pad) )
124+ } )
125+ . collect ( ) ;
126+
127+ remaining. shuffle ( rng) ;
128+
129+ let mut index = 0 ;
130+ while index + 1 < remaining. len ( ) {
131+ if remaining[ index] . 0 == remaining[ index + 1 ] . 0 {
132+ let j = remaining[ index + 2 ..]
133+ . iter ( )
134+ . position ( |( s, _, _) | * s != remaining[ index] . 0 )
135+ . expect ( "no valid cross-section partner found" ) ;
136+
137+ remaining. swap ( index + 1 , index + 2 + j) ;
138+ }
139+
140+ let ( _, pad_a, to_pad_a) = remaining[ index] ;
141+ let ( _, pad_b, to_pad_b) = remaining[ index + 1 ] ;
142+ teleport_pads. push ( TeleportPad {
143+ position : pad_a,
144+ teleports_to : to_pad_b,
145+ rotate_type : TeleportPadRotation :: TowardsEnd ,
146+ } ) ;
147+ teleport_pads. push ( TeleportPad {
148+ position : pad_b,
149+ teleports_to : to_pad_a,
150+ rotate_type : TeleportPadRotation :: TowardsEnd ,
151+ } ) ;
152+
153+ index += 2 ;
154+ }
155+
156+ Self {
157+ teleport_pads,
158+ target : pad_leading_to_end,
159+ }
160+ }
161+ }
162+
163+ impl RoomImplementation for TeleportMaze {
164+ fn discover ( & mut self , room : & mut Room , _world : & mut World < Dungeon > ) {
165+ // convert teleport pad data to absolute position
166+ for pad in self . teleport_pads . iter_mut ( ) {
167+ pad. position = room. get_world_block_position ( pad. position ) ;
168+ pad. teleports_to = room. get_world_block_position ( pad. teleports_to ) ;
169+ }
170+ self . target = room. get_world_block_position ( self . target ) ;
171+
172+ // for pad in self.teleport_pads.iter() {
173+ // _world.spawn_entity(
174+ // pad.position.as_dvec3(),
175+ // 0.0,
176+ // 0.0,
177+ // MobAppearance {
178+ // variant: EntityVariant::Zombie,
179+ // metadata: EntityMetadata::Zombie(Default::default()),
180+ // },
181+ // ()
182+ // );
183+ // }
184+ }
185+
186+ fn tick ( & mut self , room : & mut Room , world : & mut World < Dungeon > ) {
187+ // todo, improve accuracy
188+ if let DungeonState :: Started { ticks } = world. state && ticks % 10 != 0 {
189+ return ;
190+ }
191+ ' outer: for player in room. players ( ) {
192+ let player_aabb = player. collision_aabb ( ) ;
193+ for pad in self . teleport_pads . iter ( ) {
194+ if !pad. aabb ( ) . intersects ( & player_aabb) {
195+ continue
196+ }
197+
198+ let mut origin = pad. teleports_to . as_dvec3 ( ) ;
199+ origin. x += 0.5 ;
200+ origin. y += 0.5 ;
201+ origin. z += 0.5 ;
202+
203+ let yaw = match pad. rotate_type {
204+ TeleportPadRotation :: Static { yaw } => {
205+ yaw. rotate ( room. rotation )
206+ } ,
207+ TeleportPadRotation :: TowardsEnd => {
208+ let mut target = self . target . as_dvec3 ( ) ;
209+ target. x += 0.5 ;
210+ target. z += 0.5 ;
211+ let diff = target - origin;
212+ f64:: atan2 ( -diff. x , diff. z ) . to_degrees ( ) as f32
213+ }
214+ } ;
215+ player. write_packet ( & PositionLook {
216+ x : origin. x ,
217+ y : origin. y ,
218+ z : origin. z ,
219+ yaw,
220+ pitch : 0.0 ,
221+ flags : Default :: default ( ) ,
222+ } ) ;
223+ continue ' outer
224+ }
225+ }
226+ }
227+
228+ // todo interact
229+ }
230+
231+ fn pop_with_rng ( vec : & mut Vec < ( IVec3 , IVec3 ) > , rng : & mut SeededRng ) -> ( IVec3 , IVec3 ) {
232+ let pad_index = rng. random_range ( 0 ..vec. len ( ) ) ;
233+ let it = vec[ pad_index] ;
234+ vec. remove ( pad_index) ;
235+ it
236+ }
0 commit comments