Guest User

Untitled

a guest
Feb 1st, 2019
326
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.00 KB | None | 0 0
  1. /*
  2. ** 2013 October 27
  3. **
  4. ** The author disclaims copyright to this source code. In place of
  5. ** a legal notice, here is a blessing:
  6. ** May you do good and not evil.
  7. ** May you find forgiveness for yourself and forgive others.
  8. ** May you share freely, never taking more than you give.
  9. */
  10. package com.TheRPGAdventurer.ROTD.server.entity.helper;
  11.  
  12. import static com.TheRPGAdventurer.ROTD.server.entity.helper.EnumDragonLifeStage.ADULT;
  13. import static com.TheRPGAdventurer.ROTD.server.entity.helper.EnumDragonLifeStage.EGG;
  14. import static com.TheRPGAdventurer.ROTD.server.entity.helper.EnumDragonLifeStage.HATCHLING;
  15. import static com.TheRPGAdventurer.ROTD.server.entity.helper.EnumDragonLifeStage.JUVENILE;
  16. import static net.minecraft.entity.SharedMonsterAttributes.ATTACK_DAMAGE;
  17. import static net.minecraft.entity.SharedMonsterAttributes.MAX_HEALTH;
  18.  
  19. import java.util.EnumMap;
  20. import java.util.Map;
  21. import java.util.concurrent.atomic.AtomicInteger;
  22.  
  23. import org.apache.logging.log4j.LogManager;
  24. import org.apache.logging.log4j.Logger;
  25.  
  26. import com.TheRPGAdventurer.ROTD.client.blocks.BlockDragonBreedEgg;
  27. import com.TheRPGAdventurer.ROTD.client.sound.ModSounds;
  28. import com.TheRPGAdventurer.ROTD.server.entity.EntityTameableDragon;
  29. import com.TheRPGAdventurer.ROTD.server.entity.breeds.EnumDragonBreed;
  30. import com.TheRPGAdventurer.ROTD.server.entity.helper.breath.BreathNode;
  31. import com.TheRPGAdventurer.ROTD.server.util.ClientServerSynchronisedTickCount;
  32. import com.TheRPGAdventurer.ROTD.util.math.MathX;
  33.  
  34. import net.minecraft.block.Block;
  35. import net.minecraft.block.SoundType;
  36. import net.minecraft.block.material.Material;
  37. import net.minecraft.client.Minecraft;
  38. import net.minecraft.entity.ai.attributes.AttributeModifier;
  39. import net.minecraft.entity.ai.attributes.IAttribute;
  40. import net.minecraft.entity.ai.attributes.IAttributeInstance;
  41. import net.minecraft.init.Items;
  42. import net.minecraft.init.SoundEvents;
  43. import net.minecraft.item.ItemStack;
  44. import net.minecraft.nbt.NBTTagCompound;
  45. import net.minecraft.network.datasync.DataParameter;
  46. import net.minecraft.util.EnumParticleTypes;
  47. import net.minecraft.util.SoundCategory;
  48. import net.minecraft.util.math.BlockPos;
  49.  
  50. /**
  51. *
  52. * @author Nico Bergemann <barracuda415 at yahoo.de>
  53. */
  54. public class DragonLifeStageHelper extends DragonHelper {
  55.  
  56. private static final Logger L = LogManager.getLogger();
  57.  
  58. private static final String NBT_TICKS_SINCE_CREATION = "TicksSinceCreation";
  59. private static final int BLOCK_RANGE = 2;
  60. private static final int POINTS_BLOCK = 1;
  61. private static final int TICKS_SINCE_CREATION_UPDATE_INTERVAL = 100;
  62. private static final int TICK_RATE_BLOCK = 20;
  63. private static final float EGG_CRACK_THRESHOLD = 0.9f;
  64. private static final float EGG_WIGGLE_THRESHOLD = 0.75f;
  65. private static final float EGG_WIGGLE_BASE_CHANCE = 20;
  66.  
  67. private EnumDragonLifeStage lifeStagePrev;
  68. private int eggWiggleX;
  69. private int eggWiggleZ;
  70.  
  71. // the ticks since creation is used to control the dragon's life stage. It is only updated by the server occasionally.
  72. // the client keeps a cached copy of it and uses client ticks to interpolate in the gaps.
  73. // when the watcher is updated from the server, the client will tick it faster or slower to resynchronise
  74. private final DataParameter<Integer> dataParam;
  75. private final Map<EnumDragonBreed, AtomicInteger> breedPoints = new EnumMap<>(EnumDragonBreed.class);
  76. private int ticksSinceCreationServer;
  77. private final ClientServerSynchronisedTickCount ticksSinceCreationClient;
  78.  
  79. public DragonLifeStageHelper(EntityTameableDragon dragon, DataParameter<Integer> dataParam) {
  80. super(dragon);
  81.  
  82. this.dataParam = dataParam;
  83. dataWatcher.register(dataParam, ticksSinceCreationServer);
  84.  
  85. if (dragon.isClient()) {
  86. ticksSinceCreationClient = new ClientServerSynchronisedTickCount(TICKS_SINCE_CREATION_UPDATE_INTERVAL);
  87. ticksSinceCreationClient.reset(ticksSinceCreationServer);
  88. } else {
  89. ticksSinceCreationClient = null;
  90. }
  91. }
  92.  
  93. @Override
  94. public void applyEntityAttributes() {
  95. applyScaleModifier(MAX_HEALTH);
  96. applyScaleModifier(ATTACK_DAMAGE);
  97. }
  98.  
  99. private void applyScaleModifier(IAttribute attribute) {
  100. IAttributeInstance instance = dragon.getEntityAttribute(attribute);
  101. AttributeModifier oldModifier = instance.getModifier(DragonScaleModifier.ID);
  102. if (oldModifier != null) {
  103. instance.removeModifier(oldModifier);
  104. }
  105. instance.applyModifier(new DragonScaleModifier(MathX.clamp(getScale(), 0.1, 1)));
  106. }
  107.  
  108. /**
  109. * Generates some egg shell particles and a breaking sound.
  110. */
  111. public void playEggCrackEffect() {
  112. // dragon.world.playEvent(2001, dragon.getPosition(), Block.getIdFromBlock(BlockDragonBreedEgg.DRAGON_BREED_EGG));
  113. this.playEvent(dragon.getPosition(), Block.getIdFromBlock(BlockDragonBreedEgg.DRAGON_BREED_EGG));
  114. }
  115.  
  116. public void playEvent(BlockPos blockPosIn, int data) {
  117. dragon.world.playSound(null, blockPosIn, ModSounds.DRAGON_HATCHING, SoundCategory.BLOCKS, + 1.0F, 1.0F);
  118. }
  119.  
  120. public int getEggWiggleX() {
  121. return eggWiggleX;
  122. }
  123.  
  124. public int getEggWiggleZ() {
  125. return eggWiggleZ;
  126. }
  127.  
  128. /**
  129. * Returns the current life stage of the dragon.
  130. *
  131. * @return current life stage
  132. */
  133. public EnumDragonLifeStage getLifeStage() {
  134. int age = getTicksSinceCreation();
  135. return EnumDragonLifeStage.fromTickCount(age);
  136. }
  137.  
  138. public int getTicksSinceCreation() {
  139. if (dragon.isServer()) {
  140. return ticksSinceCreationServer;
  141. } else {
  142. return ticksSinceCreationClient.getCurrentTickCount();
  143. }
  144. }
  145.  
  146. public void setTicksSinceCreation(int ticksSinceCreation) {
  147. if (dragon.isServer()) {
  148. ticksSinceCreationServer = ticksSinceCreation;
  149. } else {
  150. ticksSinceCreationClient.updateFromServer(ticksSinceCreationServer);
  151. }
  152. }
  153.  
  154. @Override
  155. public void writeToNBT(NBTTagCompound nbt) {
  156. nbt.setInteger(NBT_TICKS_SINCE_CREATION, getTicksSinceCreation());
  157. }
  158.  
  159. @Override
  160. public void readFromNBT(NBTTagCompound nbt) {
  161. int ticksRead = nbt.getInteger(NBT_TICKS_SINCE_CREATION);
  162. ticksRead = EnumDragonLifeStage.clampTickCount(ticksRead);
  163. ticksSinceCreationServer = ticksRead;
  164. dataWatcher.set(dataParam, ticksSinceCreationServer);
  165. }
  166.  
  167. /**
  168. * Returns the size multiplier for the current age.
  169. *
  170. * @return size
  171. */
  172. public float getScale() {
  173. return EnumDragonLifeStage.scaleFromTickCount(getTicksSinceCreation());
  174. }
  175.  
  176. /**
  177. * Transforms the dragon to an egg (item form)
  178. */
  179. public void transformToEgg() {
  180. if (dragon.getHealth() <= 0) {
  181. // no can do
  182. return;
  183. }
  184.  
  185. L.debug("transforming to egg");
  186.  
  187. float volume = 3;
  188. float pitch = 1;
  189. dragon.playSound(SoundEvents.ENTITY_ENDERMEN_TELEPORT, volume, pitch);
  190.  
  191. if (dragon.isSaddled()) {
  192. dragon.dropItem(Items.SADDLE, 1);
  193. }
  194.  
  195. dragon.entityDropItem(new ItemStack(BlockDragonBreedEgg.DRAGON_BREED_EGG),
  196. dragon.getBreedType().getMeta());
  197.  
  198. dragon.setDead();
  199. }
  200.  
  201. /**
  202. * Sets a new life stage for the dragon.
  203. *
  204. * @param lifeStage
  205. */
  206. public final void setLifeStage(EnumDragonLifeStage lifeStage) {
  207. L.trace("setLifeStage({})", lifeStage);
  208. if (dragon.isServer()) {
  209. ticksSinceCreationServer = lifeStage.startTicks();
  210. dataWatcher.set(dataParam, ticksSinceCreationServer);
  211. } else {
  212. L.error("setLifeStage called on Client");
  213. }
  214. updateLifeStage();
  215. }
  216.  
  217. /**
  218. * Sets a new life stage for the dragon.
  219. *
  220. * @param lifeStage
  221. */
  222. public final void setLifeStageInt(int lifeStage) {
  223. L.trace("setLifeStage({})", lifeStage);
  224. if (dragon.isServer()) {
  225. ticksSinceCreationServer = lifeStage; // lifeStage.startTicks()
  226. dataWatcher.set(dataParam, ticksSinceCreationServer);
  227. } else {
  228. L.error("setLifeStage called on Client");
  229. }
  230. updateLifeStage();
  231. }
  232.  
  233. /**
  234. * Called when the dragon enters a new life stage.
  235. */
  236. private void onNewLifeStage(EnumDragonLifeStage lifeStage, EnumDragonLifeStage prevLifeStage) {
  237. L.trace("onNewLifeStage({},{})", prevLifeStage, lifeStage);
  238.  
  239. if (dragon.isClient()) {
  240. // play particle and sound effects when the dragon hatches
  241. if (prevLifeStage != null && prevLifeStage == EGG && lifeStage == HATCHLING) {
  242. playEggCrackEffect();
  243. dragon.world.playSound(dragon.posX, dragon.posY, dragon.posZ, ModSounds.DRAGON_HATCHED, SoundCategory.BLOCKS, 4, 1, false);
  244. }
  245. } else {
  246. // update AI
  247. dragon.getBrain().updateAITasks();
  248.  
  249. // update attribute modifier
  250. applyEntityAttributes();
  251.  
  252. // heal dragon to updated full health
  253. dragon.setHealth(dragon.getMaxHealth());
  254. }
  255. }
  256.  
  257. @Override
  258. public void onLivingUpdate() {
  259. // if the dragon is not an adult, update its growth ticks
  260. if (dragon.isServer()) {
  261. if (!isAdult()) {
  262. ticksSinceCreationServer++;
  263. if (ticksSinceCreationServer % TICKS_SINCE_CREATION_UPDATE_INTERVAL == 0){
  264. dataWatcher.set(dataParam, ticksSinceCreationServer);
  265. }
  266. }
  267. } else {
  268. ticksSinceCreationClient.updateFromServer(dataWatcher.get(dataParam));
  269. if (!isAdult()) {
  270. ticksSinceCreationClient.tick();
  271. }
  272. }
  273.  
  274. updateLifeStage();
  275. updateEgg();
  276. updateScale();
  277. }
  278.  
  279. private void updateLifeStage() {
  280. // trigger event when a new life stage was reached
  281. EnumDragonLifeStage lifeStage = getLifeStage();
  282. if (lifeStagePrev != lifeStage) {
  283. onNewLifeStage(lifeStage, lifeStagePrev);
  284. lifeStagePrev = lifeStage;
  285. }
  286. }
  287.  
  288. private void updateEgg() {
  289. if (!isEgg()) {
  290. return;
  291. }
  292.  
  293. // animate egg wiggle based on the time the eggs take to hatch
  294. float progress = EnumDragonLifeStage.progressFromTickCount(getTicksSinceCreation());
  295.  
  296. // wait until the egg is nearly hatched
  297. if (progress > EGG_WIGGLE_THRESHOLD) {
  298. float wiggleChance = (progress - EGG_WIGGLE_THRESHOLD) / EGG_WIGGLE_BASE_CHANCE * (1 - EGG_WIGGLE_THRESHOLD);
  299.  
  300. if (eggWiggleX > 0) {
  301. eggWiggleX--;
  302. } else if (rand.nextFloat() < wiggleChance) {
  303. eggWiggleX = rand.nextBoolean() ? 10 : 20;
  304. if (progress > EGG_CRACK_THRESHOLD) {
  305. playEggCrackEffect();
  306. }
  307. }
  308.  
  309. if (eggWiggleZ > 0) {
  310. eggWiggleZ--;
  311. } else if (rand.nextFloat() < wiggleChance) {
  312. eggWiggleZ = rand.nextBoolean() ? 10 : 20;
  313. if (progress > EGG_CRACK_THRESHOLD) {
  314. playEggCrackEffect();
  315. }
  316. }
  317. }
  318.  
  319. // spawn generic particles
  320. double px = dragon.posX + (rand.nextDouble() - 0.3);
  321. double py = dragon.posY + (rand.nextDouble() - 0.3);
  322. double pz = dragon.posZ + (rand.nextDouble() - 0.3);
  323. double ox = (rand.nextDouble() - 0.3) * 2;
  324. double oy = (rand.nextDouble() - 0.3) * 2;
  325. double oz = (rand.nextDouble() - 0.3) * 2;
  326. dragon.world.spawnParticle(this.getEggParticle(), px, py, pz, ox, oy, oz);
  327.  
  328. }
  329.  
  330. protected EnumParticleTypes getEggParticle() {
  331.  
  332. switch (dragon.getBreedType()) {
  333. case END:
  334. return EnumParticleTypes.PORTAL;
  335. case NETHER:
  336. return EnumParticleTypes.DRIP_LAVA;
  337. case FOREST:
  338. return EnumParticleTypes.TOWN_AURA;
  339. case ICE:
  340. return EnumParticleTypes.TOWN_AURA;
  341. case FIRE:
  342. return EnumParticleTypes.TOWN_AURA;
  343. case SYLPHID:
  344. return EnumParticleTypes.TOWN_AURA;
  345. case AETHER:
  346. return EnumParticleTypes.TOWN_AURA;
  347. case SKELETON:
  348. return EnumParticleTypes.TOWN_AURA;
  349. case WITHER:
  350. return EnumParticleTypes.TOWN_AURA;
  351. default:
  352. return EnumParticleTypes.TOWN_AURA;
  353.  
  354. }
  355. }
  356.  
  357. private void updateScale() {
  358. dragon.setScalePublic(getScale());
  359. }
  360.  
  361. @Override
  362. public void onDeath() {
  363. if (dragon.isClient() && isEgg()) {
  364. playEggCrackEffect();
  365. }
  366. }
  367.  
  368. public boolean isEgg() {
  369. return getLifeStage() == EGG;
  370. }
  371.  
  372. public boolean isHatchling() {
  373. return getLifeStage() == HATCHLING;
  374. }
  375.  
  376. public boolean isJuvenile() {
  377. return getLifeStage() == JUVENILE;
  378. }
  379.  
  380. public boolean isAdult() {
  381. return getLifeStage() == ADULT;
  382. }
  383.  
  384. public BreathNode.Power getBreathPower() {
  385. switch (getLifeStage()) {
  386. case EGG: {
  387. return BreathNode.Power.SMALL; // dummy
  388. }
  389. case HATCHLING: {
  390. return BreathNode.Power.SMALL;
  391. }
  392. case JUVENILE: {
  393. return BreathNode.Power.MEDIUM;
  394. }
  395. case ADULT: {
  396. return BreathNode.Power.LARGE;
  397. }
  398. default: {
  399. L.error("Illegal lifestage in getScale():" + getLifeStage());
  400. return BreathNode.Power.SMALL;
  401. }
  402. }
  403. }
  404. }
Advertisement
Add Comment
Please, Sign In to add comment