--- a/net/minecraft/world/entity/npc/WanderingTraderSpawner.java
+++ b/net/minecraft/world/entity/npc/WanderingTraderSpawner.java
@@ -38,38 +_,47 @@
 
     public WanderingTraderSpawner(ServerLevelData serverLevelData) {
         this.serverLevelData = serverLevelData;
-        this.tickDelay = 1200;
-        this.spawnDelay = serverLevelData.getWanderingTraderSpawnDelay();
-        this.spawnChance = serverLevelData.getWanderingTraderSpawnChance();
-        if (this.spawnDelay == 0 && this.spawnChance == 0) {
-            this.spawnDelay = 24000;
-            serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay);
-            this.spawnChance = 25;
-            serverLevelData.setWanderingTraderSpawnChance(this.spawnChance);
-        }
+        // Paper start - Add Wandering Trader spawn rate config options
+        this.tickDelay = Integer.MIN_VALUE;
+        // this.spawnDelay = serverLevelData.getWanderingTraderSpawnDelay();
+        // this.spawnChance = serverLevelData.getWanderingTraderSpawnChance();
+        // if (this.spawnDelay == 0 && this.spawnChance == 0) {
+        //     this.spawnDelay = 24000;
+        //     serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay);
+        //     this.spawnChance = 25;
+        //     serverLevelData.setWanderingTraderSpawnChance(this.spawnChance);
+        // }
+        // Paper end - Add Wandering Trader spawn rate config options
     }
 
     @Override
     public void tick(ServerLevel level, boolean spawnEnemies, boolean spawnFriendlies) {
+        // Paper start - Add Wandering Trader spawn rate config options
+        if (this.tickDelay == Integer.MIN_VALUE) {
+            this.tickDelay = level.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength;
+            this.spawnDelay = level.paperConfig().entities.spawning.wanderingTrader.spawnDayLength;
+            this.spawnChance = level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin;
+        }
         if (level.getGameRules().getBoolean(GameRules.RULE_DO_TRADER_SPAWNING)) {
-            if (--this.tickDelay <= 0) {
-                this.tickDelay = 1200;
-                this.spawnDelay -= 1200;
-                this.serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay);
+            if (this.tickDelay - 1 <= 0) { // Paper - Prevent tickDelay going below 0
+                this.tickDelay = level.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength;
+                this.spawnDelay = this.spawnDelay - level.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength;
+                //this.serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay); // Paper - We don't need to save this value to disk if it gets set back to a hardcoded value anyways
                 if (this.spawnDelay <= 0) {
-                    this.spawnDelay = 24000;
+                    this.spawnDelay = level.paperConfig().entities.spawning.wanderingTrader.spawnDayLength;
                     if (level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) {
                         int i = this.spawnChance;
-                        this.spawnChance = Mth.clamp(this.spawnChance + 25, 25, 75);
-                        this.serverLevelData.setWanderingTraderSpawnChance(this.spawnChance);
+                        this.spawnChance = Mth.clamp(this.spawnChance + level.paperConfig().entities.spawning.wanderingTrader.spawnChanceFailureIncrement, level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin, level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMax);
+                        //this.serverLevelData.setWanderingTraderSpawnChance(this.spawnChance); // Paper - We don't need to save this value to disk if it gets set back to a hardcoded value anyways
                         if (this.random.nextInt(100) <= i) {
                             if (this.spawn(level)) {
-                                this.spawnChance = 25;
+                                this.spawnChance = level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin;
+                                // Paper end - Add Wandering Trader spawn rate config options
                             }
                         }
                     }
                 }
-            }
+            } else { this.tickDelay--; } // Paper - Prevent tickDelay going below 0
         }
     }
 
@@ -91,14 +_,14 @@
                     return false;
                 }
 
-                WanderingTrader wanderingTrader = EntityType.WANDERING_TRADER.spawn(serverLevel, blockPos2, EntitySpawnReason.EVENT);
+                WanderingTrader wanderingTrader = EntityType.WANDERING_TRADER.spawn(serverLevel, trader -> trader.setDespawnDelay(48000), blockPos2, EntitySpawnReason.EVENT, false, false, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit // Paper - set despawnTimer before spawn events called
                 if (wanderingTrader != null) {
                     for (int i1 = 0; i1 < 2; i1++) {
                         this.tryToSpawnLlamaFor(serverLevel, wanderingTrader, 4);
                     }
 
                     this.serverLevelData.setWanderingTraderId(wanderingTrader.getUUID());
-                    wanderingTrader.setDespawnDelay(48000);
+                    // wanderingTrader.setDespawnDelay(48000); // Paper - moved above, modifiable by plugins on CreatureSpawnEvent
                     wanderingTrader.setWanderTarget(blockPos1);
                     wanderingTrader.setHomeTo(blockPos1, 16);
                     return true;
@@ -112,7 +_,7 @@
     private void tryToSpawnLlamaFor(ServerLevel serverLevel, WanderingTrader trader, int maxDistance) {
         BlockPos blockPos = this.findSpawnPositionNear(serverLevel, trader.blockPosition(), maxDistance);
         if (blockPos != null) {
-            TraderLlama traderLlama = EntityType.TRADER_LLAMA.spawn(serverLevel, blockPos, EntitySpawnReason.EVENT);
+            TraderLlama traderLlama = EntityType.TRADER_LLAMA.spawn(serverLevel, blockPos, EntitySpawnReason.EVENT, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit
             if (traderLlama != null) {
                 traderLlama.setLeashedTo(trader, true);
             }
