-
Notifications
You must be signed in to change notification settings - Fork 324
/
FloatingOrigin.cs
216 lines (171 loc) · 6.41 KB
/
FloatingOrigin.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// Project: Daggerfall Unity
// Copyright: Copyright (C) 2009-2023 Daggerfall Workshop
// Web Site: http://www.dfworkshop.net
// License: MIT License (http://www.opensource.org/licenses/mit-license.php)
// Source Code: https://github.com/Interkarma/daggerfall-unity
// Original Author: Gavin Clayton (interkarma@dfworkshop.net), LypyL
// Contributors: LypyL
//
// Notes: Interkarma 23/10/15 - Changed to trigger at map pixel boundary
// rather than a relative amount of movement. This fits better with
// serialization/deserialization which stores player position relative
// to origin of central map pixel.
//
using UnityEngine;
using System;
using DaggerfallConnect.Arena2;
using DaggerfallConnect.Utility;
using DaggerfallWorkshop.Game;
namespace DaggerfallWorkshop.Utility
{
/// <summary>
/// Moves world back to origin so central player terrain is at 0,0,0.
/// </summary>
public class FloatingOrigin : MonoBehaviour
{
#region Fields
public const int floatingOriginVersion = 3;
const float verticalThreshold = 500f;
public StreamingWorld StreamingWorld;
public GameObject Player;
public static FloatingOrigin instance;
PlayerMotor playerMotor = null;
AcrobatMotor acrobatMotor = null;
PlayerGroundMotor groundMotor = null;
DFPosition lastMapPixel;
DFPosition currentMapPixel;
#endregion
#region Properties
public DFPosition LastMapPixel
{
get { return lastMapPixel; }
}
public DFPosition CurrentMapPixel
{
get { return currentMapPixel; }
}
#endregion
#region Unity
void Awake()
{
instance = this;
Player = GameObject.FindGameObjectWithTag("Player");
if (!Player)
throw new Exception("Player object not set in FloatingOrigin script.");
if (!StreamingWorld)
throw new Exception("StreamingWorld not set in FloatingOrigin script.");
playerMotor = Player.GetComponent<PlayerMotor>();
if (!playerMotor)
throw new Exception("Player object does not have a PlayerMotor.");
acrobatMotor = Player.GetComponent<AcrobatMotor>();
if (!acrobatMotor)
throw new Exception("Player object does not have an AcrobatMotor.");
groundMotor = Player.GetComponent<PlayerGroundMotor>();
if (!groundMotor)
throw new Exception("Player object does not have a PlayerGroundMotor.");
}
void Start()
{
Initialize();
StreamingWorld.OnInitWorld += StreamingWorld_OnInitWorld;
}
void FixedUpdate()
{
// Must have streaming world reference
if (!StreamingWorld)
return;
// Do nothing during streaming world init
if (StreamingWorld.IsInit)
return;
// Get Y change
float yChange = 0;
if (playerMotor.transform.position.y < -verticalThreshold ||
playerMotor.transform.position.y > verticalThreshold)
{
yChange = -playerMotor.transform.position.y;
}
// Get X-Z (map pixel) change
float xChange = 0, zChange = 0;
if (CheckMapPosition())
{
xChange = (currentMapPixel.X - lastMapPixel.X) * (MapsFile.WorldMapTerrainDim * MeshReader.GlobalScale);
zChange = (currentMapPixel.Y - lastMapPixel.Y) * (MapsFile.WorldMapTerrainDim * MeshReader.GlobalScale);
}
// Create offset
Vector3 offset = new Vector3(-xChange, yChange, zChange);
if (offset != Vector3.zero)
{
// Offset player
OffsetPlayerController(offset);
// Offset streaming world
OffsetChildren(StreamingWorld.StreamingTarget.gameObject, offset);
// Offset loaded enemies
// Not that many in DFU, but it happens in mods
foreach (EnemyMotor enemy in ActiveGameObjectDatabase.GetActiveEnemyMotors())
enemy.AdjustLastGrounded(offset.y);
// Raise event
RaiseOnPositionUpdateEvent(offset);
}
}
#endregion
#region Public Methods
public void ChangeTargetPlayer(GameObject newPlayer)
{
if (!newPlayer)
throw new Exception("newPlayer is invalid.");
Player = newPlayer;
}
#endregion
#region Private Methods
void Initialize()
{
groundMotor.ClearActivePlatform();
DFPosition mapPixel = StreamingWorld.LocalPlayerGPS.CurrentMapPixel;
currentMapPixel = mapPixel;
lastMapPixel = mapPixel;
}
bool CheckMapPosition()
{
DFPosition mapPixel = StreamingWorld.LocalPlayerGPS.CurrentMapPixel;
if (mapPixel.X != currentMapPixel.X ||
mapPixel.Y != currentMapPixel.Y)
{
lastMapPixel = currentMapPixel;
currentMapPixel = mapPixel;
return true;
}
return false;
}
void OffsetPlayerController(Vector3 offset)
{
groundMotor.ClearActivePlatform();
acrobatMotor.AdjustFallStart(offset.y);
playerMotor.transform.position += offset;
StreamingWorld.OffsetWorldCompensation(offset, true);
}
void OffsetChildren(GameObject parent, Vector3 offset)
{
foreach (Transform child in parent.transform)
{
child.position += offset;
}
}
#endregion
#region Events
// OnPositionUpdate
public delegate void OnPositionUpdateEventHandler(Vector3 offset);
public static event OnPositionUpdateEventHandler OnPositionUpdate;
public void RaiseOnPositionUpdateEvent(Vector3 offset)
{
if (OnPositionUpdate != null)
OnPositionUpdate(offset);
}
#endregion
#region Event Handlers
private void StreamingWorld_OnInitWorld()
{
Initialize();
}
#endregion
}
}